From: mjw@wray-m-3.hpl.hp.com Date: Tue, 29 Jun 2004 18:10:39 +0000 (+0000) Subject: bitkeeper revision 1.1026.1.8 (40e1b09foCFBM0EuIgrSA1uLJrWuzA) X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~18092^2 X-Git-Url: https://dgit.raspbian.org/%22http:/www.example.com/cgi/%22https:/%22bookmarks:///%22http:/www.example.com/cgi/%22https:/%22bookmarks:/?a=commitdiff_plain;h=48e9a9c636cfbf00a1468f3a3dffe932e3e01a19;p=xen.git bitkeeper revision 1.1026.1.8 (40e1b09foCFBM0EuIgrSA1uLJrWuzA) Restructuring the python code and libs - first stage. --- diff --git a/.rootkeys b/.rootkeys index a901a1d4cd..4bff522d33 100644 --- a/.rootkeys +++ b/.rootkeys @@ -151,6 +151,7 @@ 3e5a4e681xMPdF9xCMwpyfuYMySU5g linux-2.4.26-xen-sparse/mm/mremap.c 409ba2e7akOFqQUg6Qyg2s28xcXiMg linux-2.4.26-xen-sparse/mm/page_alloc.c 3e5a4e683HKVU-sxtagrDasRB8eBVw linux-2.4.26-xen-sparse/mm/swapfile.c +40e1b09db5mN69Ijj0X_Eol-S7dXiw tools/Make.defs 3f776bd1Hy9rn69ntXBhPReUFw9IEA tools/Makefile 401d7e160vaxMBAUSLSicuZ7AQjJ3w tools/examples/Makefile 401d7e16UgeqroJQTIhwkrDVkoWgZQ tools/examples/README @@ -159,49 +160,69 @@ 405ff55dawQyCHFEnJ067ChPRoXBBA tools/examples/init.d/xend 40278d94cIUWl2eRgnwZtr4hTyWT1Q tools/examples/init.d/xendomains 40278d91ZjLhxdjjrGe8HEdwHLj5xQ tools/examples/netbsd +40e15b7edWEtBf_oe3eBwGKuh1dyzQ tools/examples/vifctl 401d7e16NpnVrFSsR7lKKKfTwCYvWA tools/examples/xc_dom_control.py 401d7e16RJj-lbtsVEjua6HYAIiKiA tools/examples/xc_dom_create.py -40c9c468pXANclL7slGaoD0kSrIwoQ tools/examples/xm_dom_create.py 40cf2937oKlROYOJTN8GWwWM5AmjBg tools/examples/xmdefaults 40dfd40auJwNnb8NoiSnRkvZaaXkUg tools/examples/xmnetbsd -40e033325Sjqs-_4TuzeUEprP_gYFg tools/lib/allocate.c -40e03332KYz7o1bn2MG_KPbBlyoIMA tools/lib/allocate.h -40e03332IyRttYoXKoJla5qCC514SQ tools/lib/debug.h -40e03332qV5tJ-GJZjo-LBCeGuEjJA tools/lib/enum.c -40e03332wwMVxfobgA1PSMTSAGLiCw tools/lib/enum.h -40e03332p5Dc_owJQRuN72ymJZddFQ tools/lib/file_stream.c -40e03332jWfB2viAhLSkq1WK0r_iDQ tools/lib/file_stream.h -40e03332rUjNMGg11n2rN6V4DCrvOg tools/lib/gzip_stream.c -40e033321O5Qg22haLoq5lpmk4tooQ tools/lib/gzip_stream.h -40e03332QrTR96tc6yS2rMBpd2mq1A tools/lib/hash_table.c -40e033325KoIb0d_uy8s7b5DUR9fPQ tools/lib/hash_table.h -40e03332ihnBGzHykVwZnFmkAppb4g tools/lib/iostream.c -40e03332UGwbLR4wsw4ft14p0Yw5pg tools/lib/iostream.h -40e0333245DLDzJemeSVBLuutHtzEQ tools/lib/kernel_stream.c -40e03332aK0GkgpDdc-PVTkWKTeOBg tools/lib/kernel_stream.h -40e03332HJ0cDcZDKDUUT-tEiBWOZw tools/lib/lexis.c -40e03332tnH9Ggzxbfi3xY9Vh2hUlg tools/lib/lexis.h -40e03332aYIW0BNBh6wXuKKn_P7Yyg tools/lib/lzi_stream.c -40e0333233voTffE4cJSMGJARfiSSQ tools/lib/lzi_stream.h -40e03332FXuMoUnfsAKSgV8X4rFbYQ tools/lib/lzo_stream.c -40e03332InJaiLfpDcIXBy2fI0RFGQ tools/lib/lzo_stream.h -40e03332a5SCuRsejHStTuWzMQNv8Q tools/lib/marshal.c -40e03332TwKyJrZQiiQfNq4vc2hpgw tools/lib/marshal.h -40e033328ccHlJuTR1FswYL_EC6LFA tools/lib/socket_stream.c -40e03332P0KVQGkmahj47aafo1X0nA tools/lib/socket_stream.h -40e03332KT_tnnoAMbPVAZBB7kSOAQ tools/lib/string_stream.c -40e03332-VtK6_OZa1vMHXFil8uq6w tools/lib/string_stream.h -40e03332dDtczi6YX7_mMxhYjJeAdQ tools/lib/sxpr.c -40e03332QPuyNKDOTIYVvkwK5qO-vg tools/lib/sxpr.h -40e03332Pi0_osJ3XPBi38ADPqdl4A tools/lib/sxpr_parser.c -40e033324v5QFMvWEXXzv38uUT9kHg tools/lib/sxpr_parser.h -40e03332gKUInsqtxQOV4mPiMqf_dg tools/lib/sys_ctype.h -40e03332Rkvq6nn_UNjzAAK_Tk9v1g tools/lib/sys_net.c -40e03332lQHvQHw4Rh7VsT1_sui29A tools/lib/sys_net.h -40e033321smklZd7bDSdWvQCeIshtg tools/lib/sys_string.c -40e03332h5V611rRWURRLqb1Ekatxg tools/lib/sys_string.h -40e03332u4q5kgF0N7RfqB4s0pZVew tools/lib/xdr.c -40e03332hY16nfRXF4gGd5S1aUJUBw tools/lib/xdr.h +3fbba6dbDfYvJSsw9500b4SZyUhxjQ tools/libxc/Makefile +3fbba6dc1uU7U3IFeF6A-XEOYF2MkQ tools/libxc/rpm.spec +3fbba6dcrNxtygEcgJYAJJ1gCQqfsA tools/libxc/xc.h +40589968oCfoUlXd460CjVAkBE8IBA tools/libxc/xc_atropos.c +3fbba6dbEVkVMX0JuDFzap9jeaucGA tools/libxc/xc_bvtsched.c +3fbba6dbasJQV-MVElDC0DGSHMiL5w tools/libxc/xc_domain.c +40278d99BLsfUv3qxv0I8C1sClZ0ow tools/libxc/xc_elf.h +403e0977Bjsm_e82pwvl9VvaJxh8Gg tools/libxc/xc_evtchn.c +40e03333Eegw8czSWvHsbKxrRZJjRA tools/libxc/xc_io.c +40e03333vrWGbLAhyJjXlqCHaJt7eA tools/libxc/xc_io.h +3fbba6dbNCU7U6nsMYiXzKkp3ztaJg tools/libxc/xc_linux_build.c +3fbba6dbl267zZOAVHYLOdLCdhcZMw tools/libxc/xc_linux_restore.c +3fbba6db7li3FJiABYtCmuGxOJxEGw tools/libxc/xc_linux_save.c +3fbba6db7WnnJr0KFrIFrqNlSKvFYg tools/libxc/xc_misc.c +40278d9ctaHVDaEuwhXI3Om2JOjx9w tools/libxc/xc_netbsd_build.c +4051bce6CHAsYh8P5t2OHDtRWOP9og tools/libxc/xc_physdev.c +3fbba6dctWRWlFJkYb6hdix2X4WMuw tools/libxc/xc_private.c +3fbba6dcbVrG2hPzEzwdeV_UC8kydQ tools/libxc/xc_private.h +40589968UQFnJeOMn8UIFLbXBuwXjw tools/libxc/xc_rrobin.c +40e1b09dMYB4ItGCqcMIzirdMd9I-w tools/libxutil/Makefile +40e033325Sjqs-_4TuzeUEprP_gYFg tools/libxutil/allocate.c +40e03332KYz7o1bn2MG_KPbBlyoIMA tools/libxutil/allocate.h +40e03332IyRttYoXKoJla5qCC514SQ tools/libxutil/debug.h +40e03332qV5tJ-GJZjo-LBCeGuEjJA tools/libxutil/enum.c +40e03332wwMVxfobgA1PSMTSAGLiCw tools/libxutil/enum.h +40e03332p5Dc_owJQRuN72ymJZddFQ tools/libxutil/file_stream.c +40e03332jWfB2viAhLSkq1WK0r_iDQ tools/libxutil/file_stream.h +40e03332rUjNMGg11n2rN6V4DCrvOg tools/libxutil/gzip_stream.c +40e033321O5Qg22haLoq5lpmk4tooQ tools/libxutil/gzip_stream.h +40e03332QrTR96tc6yS2rMBpd2mq1A tools/libxutil/hash_table.c +40e033325KoIb0d_uy8s7b5DUR9fPQ tools/libxutil/hash_table.h +40e03332ihnBGzHykVwZnFmkAppb4g tools/libxutil/iostream.c +40e03332UGwbLR4wsw4ft14p0Yw5pg tools/libxutil/iostream.h +40e0333245DLDzJemeSVBLuutHtzEQ tools/libxutil/kernel_stream.c +40e03332aK0GkgpDdc-PVTkWKTeOBg tools/libxutil/kernel_stream.h +40e03332HJ0cDcZDKDUUT-tEiBWOZw tools/libxutil/lexis.c +40e03332tnH9Ggzxbfi3xY9Vh2hUlg tools/libxutil/lexis.h +40e03332aYIW0BNBh6wXuKKn_P7Yyg tools/libxutil/lzi_stream.c +40e0333233voTffE4cJSMGJARfiSSQ tools/libxutil/lzi_stream.h +40e03332FXuMoUnfsAKSgV8X4rFbYQ tools/libxutil/lzo_stream.c +40e03332InJaiLfpDcIXBy2fI0RFGQ tools/libxutil/lzo_stream.h +40e03332a5SCuRsejHStTuWzMQNv8Q tools/libxutil/marshal.c +40e03332TwKyJrZQiiQfNq4vc2hpgw tools/libxutil/marshal.h +40e033328ccHlJuTR1FswYL_EC6LFA tools/libxutil/socket_stream.c +40e03332P0KVQGkmahj47aafo1X0nA tools/libxutil/socket_stream.h +40e03332KT_tnnoAMbPVAZBB7kSOAQ tools/libxutil/string_stream.c +40e03332-VtK6_OZa1vMHXFil8uq6w tools/libxutil/string_stream.h +40e03332dDtczi6YX7_mMxhYjJeAdQ tools/libxutil/sxpr.c +40e03332QPuyNKDOTIYVvkwK5qO-vg tools/libxutil/sxpr.h +40e03332Pi0_osJ3XPBi38ADPqdl4A tools/libxutil/sxpr_parser.c +40e033324v5QFMvWEXXzv38uUT9kHg tools/libxutil/sxpr_parser.h +40e03332gKUInsqtxQOV4mPiMqf_dg tools/libxutil/sys_ctype.h +40e03332Rkvq6nn_UNjzAAK_Tk9v1g tools/libxutil/sys_net.c +40e03332lQHvQHw4Rh7VsT1_sui29A tools/libxutil/sys_net.h +40e033321smklZd7bDSdWvQCeIshtg tools/libxutil/sys_string.c +40e03332h5V611rRWURRLqb1Ekatxg tools/libxutil/sys_string.h +40e03332u4q5kgF0N7RfqB4s0pZVew tools/libxutil/xdr.c +40e03332hY16nfRXF4gGd5S1aUJUBw tools/libxutil/xdr.h 3f776bd2Xd-dUcPKlPN2vG89VGtfvQ tools/misc/Makefile 40ab2cfawIw8tsYo0dQKtp83h4qfTQ tools/misc/fakei386xen 3f6dc136ZKOjd8PIqLbFBl_v-rnkGg tools/misc/miniterm/Makefile @@ -213,99 +234,76 @@ 3f5ef5a2dTZP0nnsFoeq2jRf3mWDDg tools/misc/xen-clone.README 3f870808zS6T6iFhqYPGelroZlVfGQ tools/misc/xen_cpuperf.c 405eedf6_nnNhFQ1I85lhCkLK6jFGA tools/misc/xencons +40c9c4697z76HDfkCLdMhmaEwzFoNQ tools/misc/xend 4056f5155QYZdsk-1fLdjsZPFTnlhg tools/misc/xensymoops.py -3fbca441SjQr8vJwTQIgH1laysaWog tools/xc/Makefile -3fbba6dbDfYvJSsw9500b4SZyUhxjQ tools/xc/lib/Makefile -3fbba6dc1uU7U3IFeF6A-XEOYF2MkQ tools/xc/lib/rpm.spec -3fbba6dcrNxtygEcgJYAJJ1gCQqfsA tools/xc/lib/xc.h -40589968oCfoUlXd460CjVAkBE8IBA tools/xc/lib/xc_atropos.c -3fbba6dbEVkVMX0JuDFzap9jeaucGA tools/xc/lib/xc_bvtsched.c -3fbba6dbasJQV-MVElDC0DGSHMiL5w tools/xc/lib/xc_domain.c -40278d99BLsfUv3qxv0I8C1sClZ0ow tools/xc/lib/xc_elf.h -403e0977Bjsm_e82pwvl9VvaJxh8Gg tools/xc/lib/xc_evtchn.c -40e03333Eegw8czSWvHsbKxrRZJjRA tools/xc/lib/xc_io.c -40e03333vrWGbLAhyJjXlqCHaJt7eA tools/xc/lib/xc_io.h -3fbba6dbNCU7U6nsMYiXzKkp3ztaJg tools/xc/lib/xc_linux_build.c -3fbba6dbl267zZOAVHYLOdLCdhcZMw tools/xc/lib/xc_linux_restore.c -3fbba6db7li3FJiABYtCmuGxOJxEGw tools/xc/lib/xc_linux_save.c -3fbba6db7WnnJr0KFrIFrqNlSKvFYg tools/xc/lib/xc_misc.c -40278d9ctaHVDaEuwhXI3Om2JOjx9w tools/xc/lib/xc_netbsd_build.c -4051bce6CHAsYh8P5t2OHDtRWOP9og tools/xc/lib/xc_physdev.c -3fbba6dctWRWlFJkYb6hdix2X4WMuw tools/xc/lib/xc_private.c -3fbba6dcbVrG2hPzEzwdeV_UC8kydQ tools/xc/lib/xc_private.h -40589968UQFnJeOMn8UIFLbXBuwXjw tools/xc/lib/xc_rrobin.c -3fbd0a3dTwnDcfdw0-v46dPbX98zDw tools/xc/py/Makefile -3fbd0a42l40lM0IICw2jXbQBVZSdZg tools/xc/py/Xc.c -3fbd0a40yT6G3M9hMpaz5xTUdl0E4g tools/xc/py/setup.py -40c9c468icGyC5RAF1bRKsCXPDCvsA tools/xen/Makefile -40dc4076hGpwa8-sWRN0jtXZeQJuKg tools/xen/lib/__init__.py -40dfd40aMOhnw_cQLve9462UR5yYxQ tools/xen/lib/ext/__init__.py -40d8915cyoVA0hJxiBFNymL7YvDaRg tools/xen/lib/util/Brctl.py -40dfd40aGqGkiopOOgJxSF4iCbHM0Q tools/xen/lib/util/__init__.py -4055ee4dwy4l0MghZosxoiu6zmhc9Q tools/xen/lib/util/console_client.py -40c9c468IienauFHQ_xJIcqnPJ8giQ tools/xen/lib/util/ip.py -4059c6a0pnxhG8hwSOivXybbGOwuXw tools/xen/lib/util/tempfile.py -40c9c468SNuObE_YWARyS0hzTPSzKg tools/xen/lib/xend/Args.py -40c9c468Um_qc66OQeLEceIz1pgD5g tools/xen/lib/xend/EventServer.py -40c9c468U8EVl0d3G--8YXVg6VJD3g tools/xen/lib/xend/EventTypes.py -40c9c468QJTEuk9g4qHxGpmIi70PEQ tools/xen/lib/xend/PrettyPrint.py -40e15b7eeQxWE_hUPB2YTgM9fsZ1PQ tools/xen/lib/xend/Vifctl.py -40c9c4688m3eqnC8fhLu1APm36VOVA tools/xen/lib/xend/XendClient.py -40c9c468t6iIKTjwuYoe-UMCikDcOQ tools/xen/lib/xend/XendConsole.py -40c9c468WnXs6eOUSff23IIGI4kMfQ tools/xen/lib/xend/XendDB.py -40c9c468fSl3H3IypyT0ppkbb0ZT9A tools/xen/lib/xend/XendDomain.py -40c9c468bbKq3uC7_fuNUkiMMjArdw tools/xen/lib/xend/XendDomainConfig.py -40c9c4685ykq87_n1kVUbMr9flx9fg tools/xen/lib/xend/XendDomainInfo.py -40c9c46854nsHmuxHQHncKk5rAs5NA tools/xen/lib/xend/XendMigrate.py -40c9c468M96gA1EYDvNa5w5kQNYLFA tools/xen/lib/xend/XendNode.py -40c9c4686jruMyZIqiaZRMiMoqMJtg tools/xen/lib/xend/XendRoot.py -40c9c468xzANp6o2D_MeCYwNmOIUsQ tools/xen/lib/xend/XendVnet.py -40c9c468x191zetrVlMnExfsQWHxIQ tools/xen/lib/xend/__init__.py -40c9c468S2YnCEKmk4ey8XQIST7INg tools/xen/lib/xend/encode.py -40c9c468DCpMe542varOolW1Xc68ew tools/xen/lib/xend/server/SrvBase.py -40c9c468IxQabrKJSWs0aEjl-27mRQ tools/xen/lib/xend/server/SrvConsole.py -40c9c4689Io5bxfbYIfRiUvsiLX0EQ tools/xen/lib/xend/server/SrvConsoleDir.py -40c9c468woSmBByfeXA4o_jGf2gCgA tools/xen/lib/xend/server/SrvDaemon.py -40c9c468kACsmkqjxBWKHRo071L26w tools/xen/lib/xend/server/SrvDeviceDir.py -40c9c468EQZJVkCLds-OhesJVVyZbQ tools/xen/lib/xend/server/SrvDir.py -40c9c468TyHZUq8sk0FF_vxM6Sozrg tools/xen/lib/xend/server/SrvDomain.py -40c9c469WzajDjutou3X7FmL9hMf3g tools/xen/lib/xend/server/SrvDomainDir.py -40c9c469-8mYEJJTAR6w_ClrJRAfwQ tools/xen/lib/xend/server/SrvEventDir.py -40c9c4694eu5759Dehr4Uhakei0EMg tools/xen/lib/xend/server/SrvNode.py -40c9c469TaZ83ypsrktmPSHLEZiP5w tools/xen/lib/xend/server/SrvRoot.py -40c9c469W3sgDMbBJYQdz5wbQweL0Q tools/xen/lib/xend/server/SrvServer.py -40c9c469aq7oXrE1Ngqf3_lBqL0RoQ tools/xen/lib/xend/server/SrvVnetDir.py -40c9c469Y_aimoOFfUZoS-4eV8gEKg tools/xen/lib/xend/server/__init__.py -40c9c4692hckPol_EK0EGB16ZyDsyQ tools/xen/lib/xend/server/blkif.py -40c9c469N2-b3GqpLHHHPZykJPLVvA tools/xen/lib/xend/server/channel.py -40c9c469hJ_IlatRne-9QEa0-wlquw tools/xen/lib/xend/server/console.py -40c9c469UcNJh_NuLU0ytorM0Lk5Ow tools/xen/lib/xend/server/controller.py -40c9c469vHh-qLiiubdbKEQbJf18Zw tools/xen/lib/xend/server/cstruct.py -40d83983OXjt-y3HjSCcuoPp9rzvmw tools/xen/lib/xend/server/domain.py -40c9c469yrm31i60pGKslTi2Zgpotg tools/xen/lib/xend/server/messages.py -40c9c46925x-Rjb0Cv2f1-l2jZrPYg tools/xen/lib/xend/server/netif.py -40c9c469ZqILEQ8x6yWy0_51jopiCg tools/xen/lib/xend/server/params.py -40c9c469LNxLVizOUpOjEaTKKCm8Aw tools/xen/lib/xend/sxp.py -40d05079aFRp6NQdo5wIh5Ly31c0cg tools/xen/lib/xm/__init__.py -40cf2937gKQcATgXKGtNeWb1PDH5nA tools/xen/lib/xm/create.py -40cf2937isyS250zyd0Q2GuEDoNXfQ tools/xen/lib/xm/main.py -40cf2937PSslwBliN1g7ofDy2H_RhA tools/xen/lib/xm/opts.py -40cf2937Z8WCNOnO2FcWdubvEAF9QQ tools/xen/lib/xm/shutdown.py -40c9c469n2RRwCmjWdjdyyVRWKmgWg tools/xen/setup.py -40e15b7edWEtBf_oe3eBwGKuh1dyzQ tools/xen/vifctl -40c9c4697z76HDfkCLdMhmaEwzFoNQ tools/xen/xend -40cf2937dqM1jWW87O5OoOYND8leuA tools/xen/xm +40cf2937dqM1jWW87O5OoOYND8leuA tools/misc/xm +40c9c468icGyC5RAF1bRKsCXPDCvsA tools/python/Makefile +40c9c469n2RRwCmjWdjdyyVRWKmgWg tools/python/setup.py +40dc4076hGpwa8-sWRN0jtXZeQJuKg tools/python/xen/__init__.py +40dfd40aMOhnw_cQLve9462UR5yYxQ tools/python/xen/ext/__init__.py +3fbd0a3dTwnDcfdw0-v46dPbX98zDw tools/python/xen/ext/xc/Makefile +3fbd0a40yT6G3M9hMpaz5xTUdl0E4g tools/python/xen/ext/xc/setup.py +3fbd0a42l40lM0IICw2jXbQBVZSdZg tools/python/xen/ext/xc/xc.c +40dc4076St6AmPTmQPrtQ6LGHPxGmw tools/python/xen/ext/xu/__init__.py +40dc4076pVeE1kEEWzcUaNZin65kCA tools/python/xen/ext/xu/domain_controller.h +40dc4076CwBYRTUQDdbdU1L6KcLgSw tools/python/xen/ext/xu/xu.c +40d8915cyoVA0hJxiBFNymL7YvDaRg tools/python/xen/util/Brctl.py +40dfd40aGqGkiopOOgJxSF4iCbHM0Q tools/python/xen/util/__init__.py +4055ee4dwy4l0MghZosxoiu6zmhc9Q tools/python/xen/util/console_client.py +40c9c468IienauFHQ_xJIcqnPJ8giQ tools/python/xen/util/ip.py +4059c6a0pnxhG8hwSOivXybbGOwuXw tools/python/xen/util/tempfile.py +40c9c468SNuObE_YWARyS0hzTPSzKg tools/python/xen/xend/Args.py +40c9c468Um_qc66OQeLEceIz1pgD5g tools/python/xen/xend/EventServer.py +40c9c468U8EVl0d3G--8YXVg6VJD3g tools/python/xen/xend/EventTypes.py +40c9c468QJTEuk9g4qHxGpmIi70PEQ tools/python/xen/xend/PrettyPrint.py +40e15b7eeQxWE_hUPB2YTgM9fsZ1PQ tools/python/xen/xend/Vifctl.py +40c9c4688m3eqnC8fhLu1APm36VOVA tools/python/xen/xend/XendClient.py +40c9c468t6iIKTjwuYoe-UMCikDcOQ tools/python/xen/xend/XendConsole.py +40c9c468WnXs6eOUSff23IIGI4kMfQ tools/python/xen/xend/XendDB.py +40c9c468fSl3H3IypyT0ppkbb0ZT9A tools/python/xen/xend/XendDomain.py +40c9c468bbKq3uC7_fuNUkiMMjArdw tools/python/xen/xend/XendDomainConfig.py +40c9c4685ykq87_n1kVUbMr9flx9fg tools/python/xen/xend/XendDomainInfo.py +40c9c46854nsHmuxHQHncKk5rAs5NA tools/python/xen/xend/XendMigrate.py +40c9c468M96gA1EYDvNa5w5kQNYLFA tools/python/xen/xend/XendNode.py +40c9c4686jruMyZIqiaZRMiMoqMJtg tools/python/xen/xend/XendRoot.py +40c9c468xzANp6o2D_MeCYwNmOIUsQ tools/python/xen/xend/XendVnet.py +40c9c468x191zetrVlMnExfsQWHxIQ tools/python/xen/xend/__init__.py +40c9c468S2YnCEKmk4ey8XQIST7INg tools/python/xen/xend/encode.py +40c9c468DCpMe542varOolW1Xc68ew tools/python/xen/xend/server/SrvBase.py +40c9c468IxQabrKJSWs0aEjl-27mRQ tools/python/xen/xend/server/SrvConsole.py +40c9c4689Io5bxfbYIfRiUvsiLX0EQ tools/python/xen/xend/server/SrvConsoleDir.py +40c9c468woSmBByfeXA4o_jGf2gCgA tools/python/xen/xend/server/SrvDaemon.py +40c9c468kACsmkqjxBWKHRo071L26w tools/python/xen/xend/server/SrvDeviceDir.py +40c9c468EQZJVkCLds-OhesJVVyZbQ tools/python/xen/xend/server/SrvDir.py +40c9c468TyHZUq8sk0FF_vxM6Sozrg tools/python/xen/xend/server/SrvDomain.py +40c9c469WzajDjutou3X7FmL9hMf3g tools/python/xen/xend/server/SrvDomainDir.py +40c9c469-8mYEJJTAR6w_ClrJRAfwQ tools/python/xen/xend/server/SrvEventDir.py +40c9c4694eu5759Dehr4Uhakei0EMg tools/python/xen/xend/server/SrvNode.py +40c9c469TaZ83ypsrktmPSHLEZiP5w tools/python/xen/xend/server/SrvRoot.py +40c9c469W3sgDMbBJYQdz5wbQweL0Q tools/python/xen/xend/server/SrvServer.py +40c9c469aq7oXrE1Ngqf3_lBqL0RoQ tools/python/xen/xend/server/SrvVnetDir.py +40c9c469Y_aimoOFfUZoS-4eV8gEKg tools/python/xen/xend/server/__init__.py +40c9c4692hckPol_EK0EGB16ZyDsyQ tools/python/xen/xend/server/blkif.py +40c9c469N2-b3GqpLHHHPZykJPLVvA tools/python/xen/xend/server/channel.py +40c9c469hJ_IlatRne-9QEa0-wlquw tools/python/xen/xend/server/console.py +40c9c469UcNJh_NuLU0ytorM0Lk5Ow tools/python/xen/xend/server/controller.py +40c9c469vHh-qLiiubdbKEQbJf18Zw tools/python/xen/xend/server/cstruct.py +40d83983OXjt-y3HjSCcuoPp9rzvmw tools/python/xen/xend/server/domain.py +40c9c469yrm31i60pGKslTi2Zgpotg tools/python/xen/xend/server/messages.py +40c9c46925x-Rjb0Cv2f1-l2jZrPYg tools/python/xen/xend/server/netif.py +40c9c469ZqILEQ8x6yWy0_51jopiCg tools/python/xen/xend/server/params.py +40c9c469LNxLVizOUpOjEaTKKCm8Aw tools/python/xen/xend/sxp.py +40d05079aFRp6NQdo5wIh5Ly31c0cg tools/python/xen/xm/__init__.py +40cf2937gKQcATgXKGtNeWb1PDH5nA tools/python/xen/xm/create.py +40cf2937isyS250zyd0Q2GuEDoNXfQ tools/python/xen/xm/main.py +40cf2937PSslwBliN1g7ofDy2H_RhA tools/python/xen/xm/opts.py +40cf2937Z8WCNOnO2FcWdubvEAF9QQ tools/python/xen/xm/shutdown.py 403a3edbrr8RE34gkbR40zep98SXbg tools/xentrace/Makefile 40a107afN60pFdURgBv9KwEzgRl5mQ tools/xentrace/formats 4050c413PhhLNAYk3TEwP37i_iLw9Q tools/xentrace/xentrace.8 403a3edbVpV2E_wq1zeEkJ_n4Uu2eg tools/xentrace/xentrace.c 403a3edblCUrzSj0mmKhO5HOPrOrSQ tools/xentrace/xentrace_format 4050c413NtuyIq5lsYJV4P7KIjujXw tools/xentrace/xentrace_format.1 -40dfd40a0QtsSGigB9TCpVGWZmhlNA tools/xu/Makefile -40dc4076St6AmPTmQPrtQ6LGHPxGmw tools/xu/lib/__init__.py -40dc4076pVeE1kEEWzcUaNZin65kCA tools/xu/lib/domain_controller.h -40dc4076CwBYRTUQDdbdU1L6KcLgSw tools/xu/lib/xu.c -40dc4076FyWUYS2nX9YufgglUzKX2A tools/xu/setup.py 3f72f1bdJPsV3JCnBqs9ddL9tr6D2g xen/COPYING 3ddb79bcbOVHh38VJzc97-JEGD4dJQ xen/Makefile 3ddb79bcWnTwYsQRWl_PaneJfa6p0w xen/Rules.mk diff --git a/BitKeeper/etc/ignore b/BitKeeper/etc/ignore index 6f52b7f4ec..a45244fe00 100644 --- a/BitKeeper/etc/ignore +++ b/BitKeeper/etc/ignore @@ -53,3 +53,22 @@ xen/xen xen/xen-syms xen/xen.* tools/xc/lib/.xc_rrobin.o.d +tools/libxc/.xc_atropos.o.d +tools/libxc/.xc_bvtsched.o.d +tools/libxc/.xc_domain.o.d +tools/libxc/.xc_evtchn.o.d +tools/libxc/.xc_io.o.d +tools/libxc/.xc_linux_build.o.d +tools/libxc/.xc_linux_restore.o.d +tools/libxc/.xc_linux_save.o.d +tools/libxc/.xc_misc.o.d +tools/libxc/.xc_netbsd_build.o.d +tools/libxc/.xc_physdev.o.d +tools/libxc/.xc_private.o.d +tools/libxc/.xc_rrobin.o.d +tools/libxutil/.allocate.o.d +tools/libxutil/.file_stream.o.d +tools/libxutil/.gzip_stream.o.d +tools/libxutil/.iostream.o.d +tools/libxutil/.sys_net.o.d +tools/libxutil/.sys_string.o.d diff --git a/tools/Make.defs b/tools/Make.defs new file mode 100644 index 0000000000..051baef2fc --- /dev/null +++ b/tools/Make.defs @@ -0,0 +1,7 @@ +# -*- mode: Makefile; -*- +XEN_HYPERVISOR_IFS = $(XEN_ROOT)/xen/include/hypervisor-ifs +XEN_LINUX_INCLUDE = $(XEN_ROOT)/linux-xen-sparse/include +XEN_XU = $(XEN_ROOT)/tools/python/xen/ext/xu +XEN_XC = $(XEN_ROOT)/tools/python/xen/ext/xc +XEN_LIBXC = $(XEN_ROOT)/tools/libxc +XEN_LIBXUTIL = $(XEN_ROOT)/tools/libxutil diff --git a/tools/Makefile b/tools/Makefile index 908f49b682..b366034eb2 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -1,29 +1,29 @@ all: - $(MAKE) -C xc - $(MAKE) -C xu + $(MAKE) -C libxutil + $(MAKE) -C libxc $(MAKE) -C misc $(MAKE) -C examples $(MAKE) -C xentrace - $(MAKE) -C xen + $(MAKE) -C python install: all - $(MAKE) -C xc install - $(MAKE) -C xu install + $(MAKE) -C libxutil install + $(MAKE) -C libxc install $(MAKE) -C misc install $(MAKE) -C examples install $(MAKE) -C xentrace install - $(MAKE) -C xen install + $(MAKE) -C python install dist: $(TARGET) $(MAKE) prefix=`pwd`/../../install dist=yes install clean: - $(MAKE) -C xc clean - $(MAKE) -C xu clean + $(MAKE) -C libxutil clean + $(MAKE) -C libxc clean $(MAKE) -C misc clean $(MAKE) -C examples clean $(MAKE) -C xentrace clean - $(MAKE) -C xen clean + $(MAKE) -C python clean diff --git a/tools/examples/Makefile b/tools/examples/Makefile index 3f7075ed1d..794933d5d6 100644 --- a/tools/examples/Makefile +++ b/tools/examples/Makefile @@ -1,21 +1,40 @@ INSTALL = $(wildcard *.py) + ETC = defaults democd netbsd xmdefaults ETCDIR = /etc/xen + INITD = init.d/xendomains init.d/xend +XEND = vifctl +XEND_DIR = $(ETCDIR)/xend + all: -install: all +install: all install-bin install-initd install-etc install-xend + +install-bin: mkdir -p $(prefix)/usr/bin + install -m0755 $(INSTALL) $(prefix)/usr/bin + +install-initd: + mkdir -p $(prefix)/etc/init.d + install -m0755 $(INITD) $(prefix)/etc/init.d + +install-etc: mkdir -p $(prefix)$(ETCDIR) mkdir -p $(prefix)$(ETCDIR)/auto - mkdir -p $(prefix)/etc/init.d - install -m0755 $(INSTALL) $(prefix)/usr/bin for i in $(ETC); \ do [ -a $(prefix)/$(ETCDIR)/$$i ] || \ install -m0644 $$i $(prefix)$(ETCDIR); \ done - install -m0755 $(INITD) $(prefix)/etc/init.d + +install-xend: + mkdir -p $(prefix)$(XEND_DIR) + for i in $(XEND); \ + do [ -a $(prefix)/$(XEND_DIR)/$$i ] || \ + install -m0755 $$i $(prefix)$(XEND_DIR); \ + done + clean: diff --git a/tools/examples/vifctl b/tools/examples/vifctl new file mode 100644 index 0000000000..d71459ed70 --- /dev/null +++ b/tools/examples/vifctl @@ -0,0 +1,149 @@ +#!/usr/bin/python +# -*- mode: python; -*- +#============================================================================ +# Xen vif control script. Lives in /etc/xen/xend. +# +# vifctl init [bridge=] [interface=] +# +# Called when xend starts up. Default behaviour is to create +# and add to it, moving its IP address to and adjusting routes. +# +# vifctl (up|down) vif= mac= [bridge=] (ipaddr=)* +# +# Called when a vif is brought up or down. Default behaviour is to add +# the vif to on up and remove it from the bridge on down. +# If ipaddr is specified, iptables rules for the ip addresses are +# added on up and removed on down. The bridge a vif is added to can +# be set in the vm config. +# +# The default bridge is nbe-br. +# The default interface is eth0. +# +#============================================================================ + +import sys +import types + +from xen.util import Brctl + +from xen.xend import XendRoot +xroot = XendRoot.instance() + +class VifControl: + + prefix = 'vifctl_' + + DEFAULT_BRIDGE = 'nbe-br' + DEFAULT_INTERFACE = 'eth0' + + def __init__(self): + self.name = 'vifctl' + + def main(self, args): + #print self.name, args + if len(args) < 2: + usage(args) + self.name = args[0] + cmd = self.prefix + args[1] + meth = getattr(self, cmd, self.unknown) + meth(args[1:]) + + def usage(self, args, out=sys.stderr): + print >>out, 'Missing command, try \n%s help' % self.name + + def unknown(self, args, out=sys.stderr): + print >>out, 'Unknown command:', args[1] + self.help(out=out) + sys.exit(1) + + def help(self, out=sys.stdout): + print >>out, 'Commands are:', + for x in vars(self): + if x.startswith(prefix): + cmd = x[len(prefix):] + print >>out, cmd, + print >>out + + def getparams(self, d, args, req=[]): + """Parse args of the form 'key=val'. Valid keys are the ones + in the dict 'd' passed in. If entries in 'd' have list values the + values of the keys are appended. + + If 'req' is specified it is a list of required keys. + """ + for x in args: + (k, v) = x.split('=') + k = k.strip() + v = v.strip() + if k not in d: + print >>sys.stderr, 'Invalid parameter: ', k + sys.exit(1) + vold = d[k] + if isinstance(vold , types.ListType): + d[k] = vold + v + else: + d[k] = v + for x in req: + if not d[x]: + print >>sys.stderr, 'Missing parameter:', x + sys.exit(1) + return d + + def vifctl_help(self, args): + self.help() + + def default_bridge(self): + return xroot.get_config_value('bridge', self.DEFAULT_BRIDGE) + + def default_interface(self): + return xroot.get_config_value('interface', self.DEFAULT_INTERFACE) + + def vifctl_init(self, args): + """Entry point for 'vifctl init'. + """ + d = { 'bridge' : self.default_bridge(), + 'interface': self.default_interface() } + params = self.getparams(d, args[1:]) + interface = params['interface'] + bridge = params['bridge'] + # Create bridge 'bridge'. + Brctl.bridge_create(bridge) + # Reconfigure so that 'interface' is added to 'bridge', + # and 'bridge' has the IP address from 'interface'. + Brctl.reconfigure(interface, bridge) + + def vifparams(self, args): + d = { 'vif' : None, + 'mac' : None, + 'bridge': self.default_bridge(), + 'ipaddr': [] } + d = self.getparams(d, args, req=['vif', 'mac']) + return d + + def vifctl_up(self, args): + """Entry point for 'vifctl up'. + """ + params = self.vifparams(args[1:]) + # Add the vif to its bridge. + Brctl.vif_bridge_add(params) + if params['ipaddr']: + # Add iptables rules for the ip addresses. + vif = params['vif'] + for ipaddr in params['ipaddr']: + Brctl.vif_restrict_addr(vif, ipaddr) + + def vifctl_down(self, args): + """Entry point for 'vifctl down'. + """ + params = self.vifparams(args[1:]) + # Remove the vif from its bridge. + Brctl.vif_bridge_rem(params) + if params['ip']: + # Remove iptables rules for the ip addresses. + vif = params['vif'] + for ip in params['ip']: + Brctl.vif_restrict_addr(vif, ip, delete=1) + + +if __name__ == "__main__": + VifControl().main(sys.argv) diff --git a/tools/examples/xm_dom_create.py b/tools/examples/xm_dom_create.py deleted file mode 100755 index d84efb1c92..0000000000 --- a/tools/examples/xm_dom_create.py +++ /dev/null @@ -1,406 +0,0 @@ -#!/usr/bin/env python - -import string -import sys -import os -import os.path -import time -import socket -import getopt -import signal -import syslog -import xenctl.ip -import xenctl.utils -import xenctl.console_client - -from xenmgr import sxp -from xenmgr import PrettyPrint -from xenmgr.XendClient import server - -config_dir = '/etc/xc/' -config_file = xc_config_file = config_dir + 'defaults' - -def main_usage (): - print >>sys.stderr,""" -Usage: %s - -This tool is used to create and start new domains. It reads defaults -from a file written in Python, having allowed variables to be set and -passed into the file. Further command line arguments allow the -defaults to be overridden. The defaults for each parameter are listed -in [] brackets. Arguments are as follows: - -Arguments to control the parsing of the defaults file: - -f config_file -- Use the specified defaults script. - Default: ['%s'] - -L state_file -- Load virtual machine memory state from state_file - -D foo=bar -- Set variable foo=bar before parsing config - E.g. '-D vmid=3;ip=1.2.3.4' - -h -- Print extended help message, including all arguments - -n -- Dry run only, don't actually create domain - Prints the config, suitable for -F. - -q -- Quiet - write output only to the system log - -F domain_config -- Build domain using the config in the file. - Suitable files can be made using '-n' to output a config. -""" % (sys.argv[0], xc_config_file) - -def extra_usage (): - print >>sys.stderr,""" -Arguments to override current config read from '%s': - -c -- Turn into console terminal after domain is created - -k image -- Path to kernel image ['%s'] - -r ramdisk -- Path to ramdisk (or empty) ['%s'] - -b builder_fn -- Function to use to build domain ['%s'] - -m mem_size -- Initial memory allocation in MB [%dMB] - -N domain_name -- Set textual name of domain ['%s'] - -a auto_restart -- Restart domain on exit, yes/no ['%d'] - -e vbd_expert -- Safety catch to avoid some disk accidents ['%s'] - -d udisk,dev,rw -- Add disk, partition, or virtual disk to domain. E.g. to - make partion sda4 available to the domain as hda1 with - read-write access: '-d phy:sda4,hda1,rw' To add - multiple disks use multiple -d flags or seperate with ';' - Default: ['%s'] - -i vfr_ipaddr -- Add IP address to the list which Xen will route to - the domain. Use multiple times to add more IP addrs. - Default: ['%s'] - -Args to override the kernel command line, which is concatenated from these: - -I cmdline_ip -- Override 'ip=ipaddr:nfsserv:gateway:netmask::eth0:off' - Default: ['%s'] - -R cmdline_root -- Override root device parameters. - Default: ['%s'] - -E cmdline_extra -- Override extra kernel args and rc script env vars. - Default: ['%s'] - -""" % (config_file, - image, ramdisk, builder_fn, mem_size, domain_name, auto_restart, - vbd_expert, - printvbds( vbd_list ), - reduce ( (lambda a,b: a+':'+b), vfr_ipaddr,'' )[1:], - cmdline_ip, cmdline_root, cmdline_extra) - -def config_usage (): pass - -def answer ( s ): - s = string.lower(s) - if s == 'yes' or s == 'true' or s == '1': return 1 - return 0 - -def printvbds ( v ): - s='' - for (a,b,c) in v: - s = s + '; %s,%s,%s' % (a,b,c) - return s[2:] - -def output(string): - global quiet - syslog.syslog(string) - if not quiet: - print string - return - -bail=False; dryrun=False; extrahelp=False; quiet = False -image=''; ramdisk=''; builder_fn='linux'; restore=0; state_file='' -mem_size=0; domain_name=''; vfr_ipaddr=[]; -vbd_expert='rr'; auto_restart=False; -vbd_list = []; cmdline_ip = ''; cmdline_root=''; cmdline_extra='' -pci_device_list = []; console_port = -1 -auto_console = False -config_from_file = False - -##### Determine location of defaults file -##### - -try: - opts, args = getopt.getopt(sys.argv[1:], "h?nqcf:F:D:k:r:b:m:N:a:e:d:i:I:R:E:L:" ) - - for opt in opts: - if opt[0] == '-f': config_file= opt[1] - if opt[0] == '-h' or opt[0] == '-?' : bail=True; extrahelp=True - if opt[0] == '-n': dryrun=True - if opt[0] == '-D': - for o in string.split( opt[1], ';' ): - (l,r) = string.split( o, '=' ) - exec "%s='%s'" % (l,r) - if opt[0] == '-q': quiet = True - if opt[0] == '-L': restore = True; state_file = opt[1] - if opt[0] == '-F': config_from_file = True; domain_config = opt[1] - - -except getopt.GetoptError: - bail=True - -if not config_from_file: - try: - os.stat( config_file ) - except: - try: - d = config_dir + config_file - os.stat( d ) - config_file = d - except: - print >> sys.stderr, "Unable to open config file '%s'" % config_file - bail = True - - -##### Parse the config file -##### - -if not config_from_file: - if not quiet: - print "Parsing config file '%s'" % config_file - - try: - execfile ( config_file ) - except (AssertionError,IOError): - print >>sys.stderr,"Exiting %s" % sys.argv[0] - bail = True - -##### Print out config if necessary -##### - -def bailout(): - global extrahelp - main_usage() - config_usage() - if extrahelp: extra_usage() - sys.exit(1) - -if bail: - bailout() - -##### Parse any command line overrides -##### - -x_vbd_list = [] -x_vfr_ipaddr = [] - -for opt in opts: - if opt[0] == '-k': image = opt[1] - if opt[0] == '-r': ramdisk = opt[1] - if opt[0] == '-b': builder_fn = opt[1] - if opt[0] == '-m': mem_size = int(opt[1]) - if opt[0] == '-C': cpu = int(opt[1]) - if opt[0] == '-N': domain_name = opt[1] - if opt[0] == '-a': auto_restart = answer(opt[1]) - if opt[0] == '-e': vbd_expert = opt[1] - if opt[0] == '-I': cmdline_ip = opt[1] - if opt[0] == '-R': cmdline_root = opt[1] - if opt[0] == '-E': cmdline_extra = opt[1] - if opt[0] == '-i': x_vfr_ipaddr.append(opt[1]) - if opt[0] == '-c': auto_console = True - if opt[0] == '-d': - try: - vv = string.split(opt[1],';') - for v in vv: - (udisk,dev,mode) = string.split(v,',') - x_vbd_list.append( (udisk,dev,mode) ) - except: - print >>sys.stderr, "Invalid block device specification : %s" % opt[1] - sys.exit(1) - -if x_vbd_list: vbd_list = x_vbd_list -if x_vfr_ipaddr: vfr_ipaddr = x_vfr_ipaddr - -syslog.openlog('xc_dom_create.py %s' % config_file, 0, syslog.LOG_DAEMON) - -def strip(pre, s): - if s.startswith(pre): - return s[len(pre):] - else: - return s - -def make_domain_config(): - global builder_fn, image, ramdisk, mem_size, domain_name - global cpu - global cmdline, cmdline_ip, cmdline_root - global vfr_ipaddr, vbd_list, vbd_expert - - config = ['config', - ['name', domain_name ], - ['memory', mem_size ], - ] - if cpu: - config.append(['cpu', cpu]) - - config_image = [ builder_fn ] - config_image.append([ 'kernel', os.path.abspath(image) ]) - if ramdisk: - config_image.append([ 'ramdisk', os.path.abspath(ramdisk) ]) - if cmdline_ip: - cmdline_ip = strip("ip=", cmdline_ip) - config_image.append(['ip', cmdline_ip]) - if cmdline_root: - cmdline_root = strip("root=", cmdline_root) - config_image.append(['root', cmdline_root]) - if cmdline_extra: - config_image.append(['args', cmdline_extra]) - config.append(['image', config_image ]) - - config_devs = [] - for (uname, dev, mode) in vbd_list: - config_vbd = ['vbd', - ['uname', uname], - ['dev', dev ], - ['mode', mode ] ] - if vbd_expert != 'rr': - config_vbd.append(['sharing', vbd_expert]) - config_devs.append(['device', config_vbd]) - - for (bus, dev, func) in pci_device_list: - config_pci = ['pci', - ['bus', bus ], - ['dev', dev ], - ['func', func] ] - config_devs.append(['device', config_pci]) - - # Add one vif with unspecified MAC. - config_devs.append(['device', ['vif']]) - - config += config_devs - - config_vfr = ['vfr'] - idx = 0 # No way of saying which IP is for which vif? - for ip in vfr_ipaddr: - config_vfr.append(['vif', ['id', idx], ['ip', ip]]) - - config.append(config_vfr) - return config - -def parse_config_file(domain_file): - config = None - fin = None - try: - fin = file(domain_file, "rb") - config = sxp.parse(fin) - if len(config) >= 1: - config = config[0] - else: - raise StandardError("Invalid configuration") - except StandardError, ex: - print >> sys.stderr, "Error :", ex - sys.exit(1) - #finally: - if fin: fin.close() - return config - -# This function creates, builds and starts a domain, using the values -# in the global variables, set above. It is used in the subsequent -# code for starting the new domain and rebooting it if appropriate. -def make_domain(config): - """Create, build and start a domain. - Returns: [int] the ID of the new domain. - """ - global restore - - if restore: - dominfo = server.xend_domain_restore(state_file, config) - else: - dominfo = server.xend_domain_create(config) - - dom = int(sxp.child_value(dominfo, 'id')) - console_info = sxp.child(dominfo, 'console') - if console_info: - console_port = int(sxp.child_value(console_info, 'port')) - else: - console_port = None - - if server.xend_domain_unpause(dom) < 0: - print "Error starting domain" - server.xend_domain_halt(dom) - sys.exit() - - return (dom, console_port) - -PID_DIR = '/var/run/xendomains/' - -def pidfile(dom): - return PID_DIR + '%d.pid' % dom - -def mkpidfile(): - global current_id - if not os.path.isdir(PID_DIR): - os.mkdir(PID_DIR) - - fd = open(pidfile(current_id), 'w') - print >> fd, str(os.getpid()) - fd.close() - return - -def rmpidfile(): - global current_id - os.unlink(pidfile(current_id)) - -def death_handler(dummy1,dummy2): - global current_id - os.unlink(pidfile(current_id)) - output('Auto-restart daemon: daemon PID = %d for domain %d is now exiting' - % (os.getpid(), current_id)) - sys.exit(0) - return - -#============================================================================ -# The starting / monitoring of the domain actually happens here... - -if config_from_file: - config = parse_config_file(domain_config) -else: - config = make_domain_config() - -if dryrun: - print "# %s" % ' '.join(sys.argv) - PrettyPrint.prettyprint(config) - sys.exit(0) -elif quiet: - pass -else: - PrettyPrint.prettyprint(config) - -# start the domain and record its ID number -(current_id, current_port) = make_domain(config) - -def start_msg(prefix, dom, port): - output(prefix + "VM started in domain %d" % dom) - if port: - output(prefix + "Console I/O available on TCP port %d." % port) - -start_msg('', current_id, current_port) - -if current_port and auto_console: - xenctl.console_client.connect('127.0.0.1', current_port) - -# if the auto_restart flag is set then keep polling to see if the domain is -# alive - restart if it is not by calling make_domain() again (it's necessary -# to update the id variable, since the new domain may have a new ID) - -#todo: Replace this - get xend to watch them. -if auto_restart: - ARD = "Auto-restart daemon: " - # turn ourselves into a background daemon - try: - pid = os.fork() - if pid > 0: - sys.exit(0) - os.setsid() - pid = os.fork() - if pid > 0: - output(ARD + 'PID = %d' % pid) - sys.exit(0) - signal.signal(signal.SIGTERM,death_handler) - except OSError: - print >> sys.stderr, ARD+'Startup failed' - sys.exit(1) - - mkpidfile() - - while True: - time.sleep(1) - # todo: use new interface - info = xc.domain_getinfo(current_id, 1) - if info == [] or info[0]['dom'] != current_id: - output(ARD + "Domain %d terminated, restarting VM in new domain" - % current_id) - rmpidfile() - (current_id, current_port) = make_domain() - mkpidfile() - start_msg(ARD, current_id, current_port) diff --git a/tools/lib/allocate.c b/tools/lib/allocate.c deleted file mode 100644 index 600ebabda6..0000000000 --- a/tools/lib/allocate.c +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2001 - 2004 Mike Wray - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "allocate.h" - -/** @file - * Support for allocating memory. - * Usable from user code or kernel code (with __KERNEL__ defined). - * In user code will use GC if USE_GC is defined. - */ - -#ifdef __KERNEL__ -/*----------------------------------------------------------------------------*/ -# include -# include -# include -# include - -# define DEFAULT_TYPE 0 -# define MALLOC(n, type) kmalloc(n, type) -# define FREE(ptr) kfree(ptr) - -/*----------------------------------------------------------------------------*/ -#else /* ! __KERNEL__ */ - -# include -# include - -# define DEFAULT_TYPE 0 - -#ifdef USE_GC -# include "gc.h" -# define MALLOC(n, typ) GC_malloc(n) -# define FREE(ptr) (ptr=NULL) -//typedef void *GC_PTR; -//GC_PTR (*GC_oom_fn)(size_t n); -#else -# define MALLOC(n, type) malloc(n) -# define FREE(ptr) free(ptr) -#endif - -/*----------------------------------------------------------------------------*/ -#endif - -/** Function to call when memory cannot be allocated. */ -AllocateFailedFn *allocate_failed_fn = NULL; - -/** Allocate memory and zero it. - * The type is only relevant when calling from kernel code, - * from user code it is ignored. - * In kernel code the values accepted by kmalloc can be used: - * GFP_USER, GFP_ATOMIC, GFP_KERNEL. - * - * @param size number of bytes to allocate - * @param type memory type to allocate (kernel only) - * @return pointer to the allocated memory or zero - * if malloc failed - */ -void *allocate_type(int size, int type){ - void *p = MALLOC(size, type); - if(p){ - memzero(p, size); - } else if(allocate_failed_fn){ - allocate_failed_fn(size, type); - } - return p; -} - -/** Allocate memory and zero it. - * - * @param size number of bytes to allocate - * @return pointer to the allocated memory or zero - * if malloc failed - */ -void *allocate(int size){ - return allocate_type(size, DEFAULT_TYPE); -} - -/** Free memory allocated by allocate(). - * No-op if 'p' is null. - * - * @param p memory to free - */ -void deallocate(void *p){ - if(p){ - FREE(p); - } -} - -/** Set bytes to zero. - * No-op if 'p' is null. - * - * @param p memory to zero - * @param size number of bytes to zero - */ -void memzero(void *p, int size){ - if(p){ - memset(p, 0, (size_t)size); - } -} - diff --git a/tools/lib/allocate.h b/tools/lib/allocate.h deleted file mode 100644 index 08bc67b910..0000000000 --- a/tools/lib/allocate.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2001 - 2004 Mike Wray - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _XEN_LIB_ALLOCATE_H_ -#define _XEN_LIB_ALLOCATE_H_ - -/** Allocate memory for a given type, and cast. */ -#define ALLOCATE(ctype) (ctype *)allocate(sizeof(ctype)) - -/** Allocate memory for a given type, and cast. */ -#define ALLOCATE_TYPE(ctype, type) (ctype *)allocate(sizeof(ctype)) - -extern void *allocate_type(int size, int type); -extern void *allocate(int size); -extern void deallocate(void *); -extern void memzero(void *p, int size); - -typedef void AllocateFailedFn(int size, int type); -extern AllocateFailedFn *allocate_failed_fn; - -#endif /* _XEN_LIB_ALLOCATE_H_ */ - - - - - - - - - diff --git a/tools/lib/debug.h b/tools/lib/debug.h deleted file mode 100644 index 4f5228faa3..0000000000 --- a/tools/lib/debug.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2004 Mike Wray - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _XEN_LIB_DEBUG_H_ -#define _XEN_LIB_DEBUG_H_ - -#ifndef MODULE_NAME -#define MODULE_NAME "" -#endif - -#ifdef __KERNEL__ -#include -#include - -#ifdef DEBUG - -#define dprintf(fmt, args...) printk(KERN_DEBUG "[DBG] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args) -#define wprintf(fmt, args...) printk(KERN_WARNING "[WRN] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args) -#define iprintf(fmt, args...) printk(KERN_INFO "[INF] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args) -#define eprintf(fmt, args...) printk(KERN_ERR "[ERR] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args) - -#else - -#define dprintf(fmt, args...) do {} while(0) -#define wprintf(fmt, args...) printk(KERN_WARNING "[WRN] " MODULE_NAME fmt, ##args) -#define iprintf(fmt, args...) printk(KERN_INFO "[INF] " MODULE_NAME fmt, ##args) -#define eprintf(fmt, args...) printk(KERN_ERR "[ERR] " MODULE_NAME fmt, ##args) - -#endif - -#else - -#include - -#ifdef DEBUG - -#define dprintf(fmt, args...) fprintf(stdout, "[DBG] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args) -#define wprintf(fmt, args...) fprintf(stderr, "[WRN] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args) -#define iprintf(fmt, args...) fprintf(stderr, "[INF] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args) -#define eprintf(fmt, args...) fprintf(stderr, "[ERR] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args) - -#else - -#define dprintf(fmt, args...) do {} while(0) -#define wprintf(fmt, args...) fprintf(stderr, "[WRN] " MODULE_NAME fmt, ##args) -#define iprintf(fmt, args...) fprintf(stderr, "[INF] " MODULE_NAME fmt, ##args) -#define eprintf(fmt, args...) fprintf(stderr, "[ERR] " MODULE_NAME fmt, ##args) - -#endif - -#endif - -/** Print format for an IP address. - * See NIPQUAD(), HIPQUAD() - */ -#define IPFMT "%u.%u.%u.%u" - -#endif /* ! _XEN_LIB_DEBUG_H_ */ diff --git a/tools/lib/enum.c b/tools/lib/enum.c deleted file mode 100644 index 95f6e31a87..0000000000 --- a/tools/lib/enum.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2002, 2004 Mike Wray - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of the - * License, or (at your option) any later version. This library is - * distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifdef __KERNEL__ -#include -#else -#include -#endif - -#include "sys_string.h" -#include "enum.h" - -/** Map an enum name to its value using a table. - * - * @param name enum name - * @param defs enum definitions - * @return enum value or -1 if not known - */ -int enum_name_to_val(char *name, EnumDef *defs){ - int val = -1; - for(; defs->name; defs++){ - if(!strcmp(defs->name, name)){ - val = defs->val; - break; - } - } - return val; -} - -/** Map an enum value to its name using a table. - * - * @param val enum value - * @param defs enum definitions - * @param defs_n number of definitions - * @return enum name or NULL if not known - */ -char *enum_val_to_name(int val, EnumDef *defs){ - char *name = NULL; - for(; defs->name; defs++){ - if(val == defs->val){ - name = defs->name; - break; - } - } - return name; -} - diff --git a/tools/lib/enum.h b/tools/lib/enum.h deleted file mode 100644 index db6e7b0058..0000000000 --- a/tools/lib/enum.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2002, 2004 Mike Wray - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of the - * License, or (at your option) any later version. This library is - * distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _XEN_LIB_ENUM_H_ -#define _XEN_LIB_ENUM_H_ - -/** Mapping of an enum value to a name. */ -typedef struct EnumDef { - int val; - char *name; -} EnumDef; - -extern int enum_name_to_val(char *name, EnumDef *defs); -extern char *enum_val_to_name(int val, EnumDef *defs); - -#endif /* _XEN_LIB_ENUM_H_ */ diff --git a/tools/lib/file_stream.c b/tools/lib/file_stream.c deleted file mode 100644 index 40391f7fa6..0000000000 --- a/tools/lib/file_stream.c +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (C) 2001 - 2004 Mike Wray - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/** @file - * An IOStream implementation using FILE*. - */ -#ifndef __KERNEL__ -#include -#include -#include "allocate.h" -#include "file_stream.h" - -static int file_read(IOStream *s, void *buf, size_t n); -static int file_write(IOStream *s, const void *buf, size_t n); -static int file_error(IOStream *s); -static int file_close(IOStream *s); -static void file_free(IOStream *s); -static int file_flush(IOStream *s); - -/** Methods used by a FILE* IOStream. */ -static const IOMethods file_methods = { - read: file_read, - write: file_write, - error: file_error, - close: file_close, - free: file_free, - flush: file_flush, -}; - -/** IOStream for stdin. */ -static IOStream _iostdin = { - methods: &file_methods, - data: (void*)1, -}; - -/** IOStream for stdout. */ -static IOStream _iostdout = { - methods: &file_methods, - data: (void*)2, -}; - -/** IOStream for stderr. */ -static IOStream _iostderr = { - methods: &file_methods, - data: (void*)3, -}; - -/** IOStream for stdin. */ -IOStream *iostdin = &_iostdin; - -/** IOStream for stdout. */ -IOStream *iostdout = &_iostdout; - -/** IOStream for stderr. */ -IOStream *iostderr = &_iostderr; - -/** Get the underlying FILE*. - * - * @param s file stream - * @return the stream s wraps - */ -static inline FILE *get_file(IOStream *s){ - switch((long)s->data){ - case 1: s->data = stdin; break; - case 2: s->data = stdout; break; - case 3: s->data = stderr; break; - } - return (FILE*)s->data; -} - -/** Control buffering on the underlying stream, like setvbuf(). - * - * @param io file stream - * @param buf buffer - * @param mode buffering mode (see man setvbuf()) - * @param size buffer size - * @return 0 on success, non-zero otherwise - */ -int file_stream_setvbuf(IOStream *io, char *buf, int mode, size_t size){ - return setvbuf(get_file(io), buf, mode, size); -} - -/** Write to the underlying stream using fwrite(); - * - * @param stream input - * @param buf where to put input - * @param n number of bytes to write - * @return number of bytes written - */ -static int file_write(IOStream *s, const void *buf, size_t n){ - return fwrite(buf, 1, n, get_file(s)); -} - -/** Read from the underlying stream using fread(); - * - * @param stream input - * @param buf where to put input - * @param n number of bytes to read - * @return number of bytes read - */ -static int file_read(IOStream *s, void *buf, size_t n){ - return fread(buf, 1, n, get_file(s)); -} - -/** Fush the underlying stream using fflush(). - * - * @param s file stream - * @return 0 on success, error code otherwise - */ -static int file_flush(IOStream *s){ - return fflush(get_file(s)); -} - -/** Check if a stream has an error. - * - * @param s file stream - * @return 1 if has an error, 0 otherwise - */ -static int file_error(IOStream *s){ - return ferror(get_file(s)); -} - -/** Close a file stream. - * - * @param s file stream to close - * @return result of the close - */ -static int file_close(IOStream *s){ - return fclose(get_file(s)); -} - -/** Free a file stream. - * - * @param s file stream - */ -static void file_free(IOStream *s){ - // Do nothing - fclose does it all? -} - -/** Create an IOStream for a stream. - * - * @param f stream to wrap - * @return new IOStream using f for i/o - */ -IOStream *file_stream_new(FILE *f){ - IOStream *io = ALLOCATE(IOStream); - if(io){ - io->methods = &file_methods; - io->data = (void*)f; - } - return io; -} - -/** IOStream version of fopen(). - * - * @param file name of the file to open - * @param flags giving the mode to open in (as for fopen()) - * @return new stream for the open file, or 0 if failed - */ -IOStream *file_stream_fopen(const char *file, const char *flags){ - IOStream *io = 0; - FILE *fin = fopen(file, flags); - if(fin){ - io = file_stream_new(fin); - if(!io){ - fclose(fin); - //free(fin); // fclose frees ? - } - } - return io; -} - -/** IOStream version of fdopen(). - * - * @param fd file descriptor - * @param flags giving the mode to open in (as for fdopen()) - * @return new stream for the open file, or 0 if failed - */ -IOStream *file_stream_fdopen(int fd, const char *flags){ - IOStream *io = 0; - FILE *fin = fdopen(fd, flags); - if(fin){ - io = file_stream_new(fin); - } - return io; -} -#endif diff --git a/tools/lib/file_stream.h b/tools/lib/file_stream.h deleted file mode 100644 index 36a0f928b2..0000000000 --- a/tools/lib/file_stream.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2001 - 2004 Mike Wray - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _XEN_LIB_FILE_STREAM_H_ -#define _XEN_LIB_FILE_STREAM_H_ - -#ifndef __KERNEL__ -#include "iostream.h" -#include - -extern IOStream *file_stream_new(FILE *f); -extern IOStream *file_stream_fopen(const char *file, const char *flags); -extern IOStream *file_stream_fdopen(int fd, const char *flags); -extern IOStream get_stream_stdout(void); -extern IOStream get_stream_stderr(void); -extern IOStream get_stream_stdin(void); - -extern int file_stream_setvbuf(IOStream *io, char *buf, int mode, size_t size); -#endif -#endif /* !_XEN_LIB_FILE_STREAM_H_ */ diff --git a/tools/lib/gzip_stream.c b/tools/lib/gzip_stream.c deleted file mode 100644 index af46023f9d..0000000000 --- a/tools/lib/gzip_stream.c +++ /dev/null @@ -1,171 +0,0 @@ -/* $Id: gzip_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $ */ -/* - * Copyright (C) 2003 Hewlett-Packard Company. - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/** @file - * An IOStream implementation using zlib gzFile to provide - * compression and decompression. - */ -#ifndef __KERNEL__ - -#include -#include - -#include "zlib.h" - -#include "allocate.h" -#include "gzip_stream.h" - -static int gzip_read(IOStream *s, void *buf, size_t n); -static int gzip_write(IOStream *s, const void *buf, size_t n); -static int gzip_error(IOStream *s); -static int gzip_close(IOStream *s); -static void gzip_free(IOStream *s); -static int gzip_flush(IOStream *s); - -/** Methods used by a gzFile* IOStream. */ -static const IOMethods gzip_methods = { - read: gzip_read, - write: gzip_write, - error: gzip_error, - close: gzip_close, - free: gzip_free, - flush: gzip_flush, -}; - -/** Get the underlying gzFile*. - * - * @param s gzip stream - * @return the stream s wraps - */ -static inline gzFile get_gzfile(IOStream *s){ - return (gzFile)s->data; -} - -/** Write to the underlying stream. - * - * @param stream destination - * @param buf data - * @param n number of bytes to write - * @return number of bytes written - */ -static int gzip_write(IOStream *s, const void *buf, size_t n){ - return gzwrite(get_gzfile(s), (void*)buf, n); -} - -/** Read from the underlying stream. - * - * @param stream input - * @param buf where to put input - * @param n number of bytes to read - * @return number of bytes read - */ -static int gzip_read(IOStream *s, void *buf, size_t n){ - return gzread(get_gzfile(s), buf, n); -} - -/** Flush the underlying stream. - * - * @param s gzip stream - * @return 0 on success, error code otherwise - */ -static int gzip_flush(IOStream *s){ - //return gzflush(get_gzfile(s), Z_NO_FLUSH); - return gzflush(get_gzfile(s), Z_SYNC_FLUSH); - //return gzflush(get_gzfile(s), Z_FULL_FLUSH); -} - -/** Check if a stream has an error. - * - * @param s gzip stream - * @return 1 if has an error, 0 otherwise - */ -static int gzip_error(IOStream *s){ - int err; - gzFile *gz = get_gzfile(s); - gzerror(gz, &err); - return (err == Z_ERRNO ? 1 /* ferror(gzfile(gz)) */ : err); -} - -/** Close a gzip stream. - * - * @param s gzip stream to close - * @return result of the close - */ -static int gzip_close(IOStream *s){ - return gzclose(get_gzfile(s)); -} - -/** Free a gzip stream. - * - * @param s gzip stream - */ -static void gzip_free(IOStream *s){ - // Do nothing - fclose does it all? -} - -/** Create an IOStream for a gzip stream. - * - * @param f stream to wrap - * @return new IOStream using f for i/o - */ -IOStream *gzip_stream_new(gzFile *f){ - IOStream *io = ALLOCATE(IOStream); - if(io){ - io->methods = &gzip_methods; - io->data = (void*)f; - } - return io; -} - -/** IOStream version of fopen(). - * - * @param file name of the file to open - * @param flags giving the mode to open in (as for fopen()) - * @return new stream for the open file, or NULL if failed - */ -IOStream *gzip_stream_fopen(const char *file, const char *flags){ - IOStream *io = NULL; - gzFile *fgz; - fgz = gzopen(file, flags); - if(fgz){ - io = gzip_stream_new(fgz); - if(!io){ - gzclose(fgz); - //free(fgz); // gzclose frees ? - } - } - return io; -} - -/** IOStream version of fdopen(). - * - * @param fd file descriptor - * @param flags giving the mode to open in (as for fdopen()) - * @return new stream for the open file, or NULL if failed - */ -IOStream *gzip_stream_fdopen(int fd, const char *flags){ - IOStream *io = NULL; - gzFile *fgz; - fgz = gzdopen(fd, flags); - if(fgz){ - io = gzip_stream_new(fgz); - } - return io; -} -#endif diff --git a/tools/lib/gzip_stream.h b/tools/lib/gzip_stream.h deleted file mode 100644 index cf76d25275..0000000000 --- a/tools/lib/gzip_stream.h +++ /dev/null @@ -1,31 +0,0 @@ -#/* $Id: gzip_stream.h,v 1.3 2003/09/30 15:22:53 mjw Exp $ */ -/* - * Copyright (C) 2003 Hewlett-Packard Company. - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _SP_GZIP_STREAM_H_ -#define _SP_GZIP_STREAM_H_ - -#ifndef __KERNEL__ -#include "iostream.h" -#include "zlib.h" - -extern IOStream *gzip_stream_new(gzFile *f); -extern IOStream *gzip_stream_fopen(const char *file, const char *flags); -extern IOStream *gzip_stream_fdopen(int fd, const char *flags); -#endif -#endif /* !_SP_FILE_STREAM_H_ */ diff --git a/tools/lib/hash_table.c b/tools/lib/hash_table.c deleted file mode 100644 index 13da946e77..0000000000 --- a/tools/lib/hash_table.c +++ /dev/null @@ -1,640 +0,0 @@ -/* - * Copyright (C) 2001 - 2004 Mike Wray - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifdef __KERNEL__ -# include -# include -# include -# include -#else -# include -# include -#endif - -//#include - -#include "allocate.h" -#include "hash_table.h" - -/** @file - * Base support for hashtables. - * - * Hash codes are reduced modulo the number of buckets to index tables, - * so there is no need for hash functions to limit the range of hashcodes. - * In fact it is assumed that hashcodes do not change when the number of - * buckets in the table changes. - */ - -/*==========================================================================*/ -/** Number of bits in half a word. */ -//#if __WORDSIZE == 64 -//#define HALF_WORD_BITS 32 -//#else -#define HALF_WORD_BITS 16 -//#endif - -/** Mask for lo half of a word. On 32-bit this is - * (1<<16) - 1 = 65535 = 0xffff - * It's 4294967295 = 0xffffffff on 64-bit. - */ -#define LO_HALF_MASK ((1 << HALF_WORD_BITS) - 1) - -/** Get the lo half of a word. */ -#define LO_HALF(x) ((x) & LO_HALF_MASK) - -/** Get the hi half of a word. */ -#define HI_HALF(x) ((x) >> HALF_WORD_BITS) - -/** Do a full hash on both inputs, using DES-style non-linear scrambling. - * Both inputs are replaced with the results of the hash. - * - * @param pleft input/output word - * @param pright input/output word - */ -void pseudo_des(unsigned long *pleft, unsigned long *pright){ - // Bit-rich mixing constant. - static const unsigned long a_mixer[] = { - 0xbaa96887L, 0x1e17d32cL, 0x03bcdc3cL, 0x0f33d1b2L, }; - - // Bit-rich mixing constant. - static const unsigned long b_mixer[] = { - 0x4b0f3b58L, 0xe874f0c3L, 0x6955c5a6L, 0x55a7ca46L, }; - - // Number of iterations - must be 2 or 4. - static const int ncycle = 4; - //static const int ncycle = 2; - - unsigned long left = *pleft, right = *pright; - unsigned long v, v_hi, v_lo; - int i; - - for(i=0; ibuckets + (hashcode % table->buckets_n); -} - -/** Initialize a hash table. - * Can be safely called more than once. - * - * @param table to initialize - */ -void HashTable_init(HashTable *table){ - int i; - - if(!table->init_done){ - table->init_done = 1; - table->next_id = 0; - for(i=0; ibuckets_n; i++){ - HTBucket *bucket = get_bucket(table, i); - bucket->head = 0; - bucket->count = 0; - } - table->entry_count = 0; - } -} - -/** Allocate a new hashtable. - * If the number of buckets is not positive the default is used. - * The number of buckets should usually be prime. - * - * @param buckets_n number of buckets - * @return new hashtable or null - */ -HashTable *HashTable_new(int buckets_n){ - HashTable *z = ALLOCATE(HashTable); - if(!z) goto exit; - if(buckets_n <= 0){ - buckets_n = HT_BUCKETS_N; - } - z->buckets = (HTBucket*)allocate(buckets_n * sizeof(HTBucket)); - if(!z->buckets){ - deallocate(z); - z = 0; - goto exit; - } - z->buckets_n = buckets_n; - HashTable_init(z); - exit: - return z; -} - -/** Free a hashtable. - * Any entries are removed and freed. - * - * @param h hashtable (ignored if null) - */ -void HashTable_free(HashTable *h){ - if(h){ - HashTable_clear(h); - deallocate(h->buckets); - deallocate(h); - } -} - -/** Push an entry on the list in the bucket for a given hashcode. - * - * @param table to add entry to - * @param hashcode for the entry - * @param entry to add - */ -static inline void push_on_bucket(HashTable *table, Hashcode hashcode, - HTEntry *entry){ - HTBucket *bucket; - HTEntry *old_head; - - bucket = get_bucket(table, hashcode); - old_head = bucket->head; - bucket->count++; - bucket->head = entry; - entry->next = old_head; -} - -/** Change the number of buckets in a hashtable. - * No-op if the number of buckets is not positive. - * Existing entries are reallocated to buckets based on their hashcodes. - * The table is unmodified if the number of buckets cannot be changed. - * - * @param table hashtable - * @param buckets_n new number of buckets - * @return 0 on success, error code otherwise - */ -int HashTable_set_buckets_n(HashTable *table, int buckets_n){ - int err = 0; - HTBucket *old_buckets = table->buckets; - int old_buckets_n = table->buckets_n; - int i; - - if(buckets_n <= 0){ - err = -EINVAL; - goto exit; - } - table->buckets = (HTBucket*)allocate(buckets_n * sizeof(HTBucket)); - if(!table->buckets){ - err = -ENOMEM; - table->buckets = old_buckets; - goto exit; - } - table->buckets_n = buckets_n; - for(i=0; ihead; entry; entry = next){ - next = entry->next; - push_on_bucket(table, entry->hashcode, entry); - } - } - deallocate(old_buckets); - exit: - return err; -} - -/** Adjust the number of buckets so the table is neither too full nor too empty. - * The table is unmodified if adjusting fails. - * - * @param table hash table - * @param buckets_min minimum number of buckets (use default if 0 or negative) - * @return 0 on success, error code otherwise - */ -int HashTable_adjust(HashTable *table, int buckets_min){ - int buckets_n = 0; - int err = 0; - if(buckets_min <= 0) buckets_min = HT_BUCKETS_N; - if(table->entry_count >= table->buckets_n){ - // The table is dense - expand it. - buckets_n = 2 * table->buckets_n; - } else if((table->buckets_n > buckets_min) && - (4 * table->entry_count < table->buckets_n)){ - // The table is more than minimum size and sparse - shrink it. - buckets_n = 2 * table->entry_count; - if(buckets_n < buckets_min) buckets_n = buckets_min; - } - if(buckets_n){ - err = HashTable_set_buckets_n(table, buckets_n); - } - return err; -} - -/** Allocate a new entry for a given value. - * - * @param value to put in the entry - * @return entry, or 0 on failure - */ -HTEntry * HTEntry_new(Hashcode hashcode, void *key, void *value){ - HTEntry *z = ALLOCATE(HTEntry); - if(z){ - z->hashcode = hashcode; - z->key = key; - z->value = value; - } - return z; -} - -/** Free an entry. - * - * @param z entry to free - */ -inline void HTEntry_free(HTEntry *z){ - if(z){ - deallocate(z); - } -} - -/** Free an entry in a hashtable. - * The table's entry_free_fn is used is defined, otherwise - * the HTEntry itself is freed. - * - * @param table hashtable - * @param entry to free - */ -inline void HashTable_free_entry(HashTable *table, HTEntry *entry){ - if(!entry)return; - if(table && table->entry_free_fn){ - table->entry_free_fn(table, entry); - } else { - HTEntry_free(entry); - } -} - -/** Get the first entry satisfying a test from the bucket for the - * given hashcode. - * - * @param table to look in - * @param hashcode indicates the bucket - * @param test_fn test to apply to elements - * @param arg first argument to calls to test_fn - * @return entry found, or 0 - */ -inline HTEntry * HashTable_find_entry(HashTable *table, Hashcode hashcode, - TableTestFn *test_fn, TableArg arg){ - HTBucket *bucket; - HTEntry *entry = 0; - HTEntry *next; - - bucket = get_bucket(table, hashcode); - for(entry = bucket->head; entry; entry = next){ - next = entry->next; - if(test_fn(arg, table, entry)){ - break; - } - } - return entry; -} - -/** Test hashtable keys for equality. - * Uses the table's key_equal_fn if defined, otherwise pointer equality. - * - * @param key1 key to compare - * @param key2 key to compare - * @return 1 if equal, 0 otherwise - */ -inline int HashTable_key_equal(HashTable *table, void *key1, void *key2){ - return (table->key_equal_fn ? table->key_equal_fn(key1, key2) : key1==key2); -} - -/** Compute the hashcode of a hashtable key. - * The table's key_hash_fn is used if defined, otherwise the address of - * the key is hashed. - * - * @param table hashtable - * @param key to hash - * @return hashcode - */ -inline Hashcode HashTable_key_hash(HashTable *table, void *key){ - return (table->key_hash_fn ? table->key_hash_fn(key) : hash_ul((unsigned long)key)); -} - -/** Test if an entry has a given key. - * - * @param arg containing key to test for - * @param table the entry is in - * @param entry to test - * @return 1 if the entry has the key, 0 otherwise - */ -static inline int has_key(TableArg arg, HashTable *table, HTEntry *entry){ - return HashTable_key_equal(table, arg.ptr, entry->key); -} - -/** Get an entry with a given key. - * - * @param table to search - * @param key to look for - * @return entry if found, null otherwise - */ -#if 0 -inline HTEntry * HashTable_get_entry(HashTable *table, void *key){ - TableArg arg = { ptr: key }; - return HashTable_find_entry(table, HashTable_key_hash(table, key), has_key, arg); -} -#else -inline HTEntry * HashTable_get_entry(HashTable *table, void *key){ - Hashcode hashcode; - HTBucket *bucket; - HTEntry *entry = 0; - HTEntry *next; - - hashcode = HashTable_key_hash(table, key); - bucket = get_bucket(table, hashcode); - for(entry = bucket->head; entry; entry = next){ - next = entry->next; - if(HashTable_key_equal(table, key, entry->key)){ - break; - } - } - return entry; -} -#endif - -/** Get the value of an entry with a given key. - * - * @param table to search - * @param key to look for - * @return value if an entry was found, null otherwise - */ -inline void * HashTable_get(HashTable *table, void *key){ - HTEntry *entry = HashTable_get_entry(table, key); - return (entry ? entry->value : 0); -} - -/** Print the buckets in a table. - * - * @param table to print - */ -void show_buckets(HashTable *table, IOStream *io){ - int i,j ; - IOStream_print(io, "entry_count=%d buckets_n=%d\n", table->entry_count, table->buckets_n); - for(i=0; ibuckets_n; i++){ - if(0 || table->buckets[i].count>0){ - IOStream_print(io, "bucket %3d %3d %10p ", i, - table->buckets[i].count, - table->buckets[i].head); - for(j = table->buckets[i].count; j>0; j--){ - IOStream_print(io, "+"); - } - IOStream_print(io, "\n"); - } - } - HashTable_print(table, io); -} - -/** Print an entry in a table. - * - * @param entry to print - * @param arg a pointer to an IOStream to print to - * @return 0 - */ -static int print_entry(TableArg arg, HashTable *table, HTEntry *entry){ - IOStream *io = (IOStream*)arg.ptr; - IOStream_print(io, " b=%4lx h=%08lx i=%08lx |-> e=%8p k=%8p v=%8p\n", - entry->hashcode % table->buckets_n, - entry->hashcode, - entry->index, - entry, entry->key, entry->value); - return 0; -} - -/** Print a hash table. - * - * @param table to print - */ -void HashTable_print(HashTable *table, IOStream *io){ - IOStream_print(io, "{\n"); - HashTable_map(table, print_entry, (TableArg){ ptr: io }); - IOStream_print(io, "}\n"); -} -/*==========================================================================*/ - -/** Get the next entry id to use for a table. - * - * @param table hash table - * @return non-zero entry id - */ -static inline unsigned long get_next_id(HashTable *table){ - unsigned long id; - - if(table->next_id == 0){ - table->next_id = 1; - } - id = table->next_id++; - return id; -} - -/** Add an entry to the bucket for the - * given hashcode. - * - * @param table to insert in - * @param hashcode indicates the bucket - * @param key to add an entry for - * @param value to add an entry for - * @return entry on success, 0 on failure - */ -inline HTEntry * HashTable_add_entry(HashTable *table, Hashcode hashcode, void *key, void *value){ - HTEntry *entry = HTEntry_new(hashcode, key, value); - if(entry){ - entry->index = get_next_id(table); - push_on_bucket(table, hashcode, entry); - table->entry_count++; - } - return entry; -} - -/** Move the front entry for a bucket to the correct point in the bucket order as - * defined by the order function. If this is called every time a new entry is added - * the bucket will be maintained in sorted order. - * - * @param table to modify - * @param hashcode indicates the bucket - * @param order entry comparison function - * @return 0 if an entry was moved, 1 if not - */ -int HashTable_order_bucket(HashTable *table, Hashcode hashcode, TableOrderFn *order){ - HTEntry *new_entry = NULL, *prev = NULL, *entry = NULL; - HTBucket *bucket; - int err = 1; - - bucket = get_bucket(table, hashcode); - new_entry = bucket->head; - if(!new_entry || !new_entry->next) goto exit; - for(entry = new_entry->next; entry; prev = entry, entry = entry->next){ - if(order(new_entry, entry) <= 0) break; - } - if(prev){ - err = 0; - bucket->head = new_entry->next; - new_entry->next = entry; - prev->next = new_entry; - } - exit: - return err; -} - -/** Add an entry to a hashtable. - * The entry is added to the bucket for its key's hashcode. - * - * @param table to insert in - * @param key to add an entry for - * @param value to add an entry for - * @return entry on success, 0 on failure - */ -inline HTEntry * HashTable_add(HashTable *table, void *key, void *value){ - return HashTable_add_entry(table, HashTable_key_hash(table, key), key, value); -} - - -/** Remove entries satisfying a test from the bucket for the - * given hashcode. - * - * @param table to remove from - * @param hashcode indicates the bucket - * @param test_fn test to apply to elements - * @param arg first argument to calls to test_fn - * @return number of entries removed - */ -inline int HashTable_remove_entry(HashTable *table, Hashcode hashcode, - TableTestFn *test_fn, TableArg arg){ - HTBucket *bucket; - HTEntry *entry, *prev = 0, *next; - int removed_count = 0; - - bucket = get_bucket(table, hashcode); - for(entry = bucket->head; entry; entry = next){ - next = entry->next; - if(test_fn(arg, table, entry)){ - if(prev){ - prev->next = next; - } else { - bucket->head = next; - } - bucket->count--; - table->entry_count--; - removed_count++; - HashTable_free_entry(table, entry); - entry = 0; - } - prev = entry; - } - return removed_count; -} - -/** Remove entries with a given key. - * - * @param table to remove from - * @param key of entries to remove - * @return number of entries removed - */ -inline int HashTable_remove(HashTable *table, void *key){ -#if 1 - Hashcode hashcode; - HTBucket *bucket; - HTEntry *entry, *prev = 0, *next; - int removed_count = 0; - - hashcode = HashTable_key_hash(table, key); - bucket = get_bucket(table, hashcode); - for(entry = bucket->head; entry; entry = next){ - next = entry->next; - if(HashTable_key_equal(table, key, entry->key)){ - if(prev){ - prev->next = next; - } else { - bucket->head = next; - } - bucket->count--; - table->entry_count--; - removed_count++; - HashTable_free_entry(table, entry); - entry = 0; - } - prev = entry; - } - return removed_count; -#else - return HashTable_remove_entry(table, HashTable_key_hash(table, key), - has_key, (TableArg){ ptr: key}); -#endif -} - -/** Remove (and free) all the entries in a bucket. - * - * @param bucket to clear - */ -static inline void bucket_clear(HashTable *table, HTBucket *bucket){ - HTEntry *entry, *next; - - for(entry = bucket->head; entry; entry = next){ - next = entry->next; - HashTable_free_entry(table, entry); - } - bucket->head = 0; - table->entry_count -= bucket->count; - bucket->count = 0; -} - -/** Remove (and free) all the entries in a table. - * - * @param table to clear - */ -void HashTable_clear(HashTable *table){ - int i, n = table->buckets_n; - - for(i=0; ibuckets + i); - } -} diff --git a/tools/lib/hash_table.h b/tools/lib/hash_table.h deleted file mode 100644 index 6d7e76ff33..0000000000 --- a/tools/lib/hash_table.h +++ /dev/null @@ -1,295 +0,0 @@ -/* $Id: hash_table.h,v 1.1 2004/03/30 16:21:26 mjw Exp $ */ -/* - * Copyright (C) 2001 - 2004 Mike Wray - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _XEN_LIB_HASH_TABLE_H_ -#define _XEN_LIB_HASH_TABLE_H_ - -#include "iostream.h" - -typedef unsigned long Hashcode; - -/** Type used to pass parameters to table functions. */ -typedef union TableArg { - unsigned long ul; - void *ptr; -} TableArg; - -/** An entry in a bucket list. */ -typedef struct HTEntry { - /** Hashcode of the entry's key. */ - Hashcode hashcode; - /** Identifier for this entry in the table. */ - int index; - /** The key for this entry. */ - void *key; - /** The value in this entry. */ - void *value; - /** The next entry in the list. */ - struct HTEntry *next; -} HTEntry; - -/** A bucket in a rule table. */ -typedef struct HTBucket { - /** Number of entries in the bucket. */ - int count; - /** First entry in the bucket (may be null). */ - HTEntry *head; -} HTBucket; - -/** Default number of buckets in a hash table. - * You want enough buckets so the lists in the buckets will typically be short. - * It's a good idea if this is prime, since that will help to spread hashcodes - * around the table. - */ -//#define HT_BUCKETS_N 1 -//#define HT_BUCKETS_N 3 -//#define HT_BUCKETS_N 7 -//#define HT_BUCKETS_N 17 -//#define HT_BUCKETS_N 97 -//#define HT_BUCKETS_N 211 -//#define HT_BUCKETS_N 401 -#define HT_BUCKETS_N 1021 - -typedef struct HashTable HashTable; - -/** Type for a function used to select table entries. */ -typedef int TableTestFn(TableArg arg, HashTable *table, HTEntry *entry); - -/** Type for a function to map over table entries. */ -typedef int TableMapFn(TableArg arg, HashTable *table, HTEntry *entry); - -/** Type for a function to free table entries. */ -typedef void TableFreeFn(HashTable *table, HTEntry *entry); - -/** Type for a function to hash table keys. */ -typedef Hashcode TableHashFn(void *key); - -/** Type for a function to test table keys for equality. */ -typedef int TableEqualFn(void *key1, void *key2); - -/** Type for a function to order table entries. */ -typedef int TableOrderFn(HTEntry *e1, HTEntry *e2); - -/** General hash table. - * A hash table with a list in each bucket. - * Functions can be supplied for freeing entries, hashing keys, and comparing keys. - * These all default to 0, when default behaviour treating keys as integers is used. - */ -struct HashTable { - /** Flag indicating whether the table has been initialised. */ - int init_done; - /** Next value for the id field in inserted rules. */ - unsigned long next_id; - /** Number of buckets in the bucket array. */ - int buckets_n; - /** Array of buckets, each with its own list. */ - HTBucket *buckets; - /** Number of entries in the table. */ - int entry_count; - /** Function to free keys and values in entries. */ - TableFreeFn *entry_free_fn; - /** Function to hash keys. */ - TableHashFn *key_hash_fn; - /** Function to compare keys for equality. */ - TableEqualFn *key_equal_fn; - /** Place for the user of the table to hang extra data. */ - void *user_data; -}; - -extern HashTable *HashTable_new(int bucket_n); -extern void HashTable_free(HashTable *table); -extern HTEntry * HTEntry_new(Hashcode hashcode, void *key, void *value); -extern void HTEntry_free(HTEntry *entry); -extern int HashTable_set_bucket_n(HashTable *table, int bucket_n); -extern void HashTable_clear(HashTable *table); -extern HTEntry * HashTable_add_entry(HashTable *table, Hashcode hashcode, void *key, void *value); -extern HTEntry * HashTable_get_entry(HashTable *table, void *key); -extern HTEntry * HashTable_add(HashTable *table, void *key, void *value); -extern void * HashTable_get(HashTable *table, void *key); -extern int HashTable_remove(HashTable *table, void *key); -extern HTEntry * HashTable_find_entry(HashTable *table, Hashcode hashcode, - TableTestFn *test_fn, TableArg arg); -extern int HashTable_remove_entry(HashTable *table, Hashcode hashcode, - TableTestFn *test_fn, TableArg arg); -//extern int HashTable_map(HashTable *table, TableMapFn *map_fn, TableArg arg); -extern void HashTable_print(HashTable *table, IOStream *out); -extern int HashTable_set_buckets_n(HashTable *table, int buckets_n); -extern int HashTable_adjust(HashTable *table, int buckets_min); -extern void pseudo_des(unsigned long *pleft, unsigned long *pright); -extern Hashcode hash_string(char *s); - -extern int HashTable_order_bucket(HashTable *table, Hashcode hashcode, TableOrderFn *order); - -/** Control whether to use hashing based on DES or simple - * hashing. DES hashing is `more random' but much more expensive. - */ -#define HASH_PSEUDO_DES 0 - -/** Hash a long using a quick and dirty linear congruential random number generator. - * See `Numerical Recipes in C', Chapter 7, "An Even Quicker Generator". - * - * @param a value to hash - * @return hashed input - */ -static inline unsigned long lcrng_hash(unsigned long a){ - return (1664525L * a + 1013904223L); -} - -/** Hash an unsigned long. - * - * @param a input to hash - * @return hashcode - */ -static inline Hashcode hash_ul(unsigned long a){ -#if HASH_PSEUDO_DES - unsigned long left = a; - unsigned long right = 0L; - pseudo_des(&left, &right); - return right; -#else - a = lcrng_hash(a); - a = lcrng_hash(a); - return a; -#endif -} - -/** Hash two unsigned longs together. - * - * @param a input to hash - * @param b input to hash - * @return hashcode - */ -static inline Hashcode hash_2ul(unsigned long a, unsigned long b){ -#if HASH_PSEUDO_DES - unsigned long left = a; - unsigned long right = b; - pseudo_des(&left, &right); - return right; -#else - a = lcrng_hash(a); - a ^= b; - a = lcrng_hash(a); - return a; -#endif -} - -/** Hash a hashcode and an unsigned long together. - * - * @param a input hashcode - * @param b input to hash - * @return hashcode - */ -static inline Hashcode hash_hul(Hashcode a, unsigned long b){ -#if HASH_PSEUDO_DES - unsigned long left = a; - unsigned long right = b; - pseudo_des(&left, &right); - return right; -#else - a ^= b; - a = lcrng_hash(a); - return a; -#endif -} - -/** Macro to declare variables for HashTable_for_each() to use. - * - * @param entry variable that is set to entries in the table - */ -#define HashTable_for_decl(entry) \ - HashTable *_var_table; \ - HTBucket *_var_bucket; \ - HTBucket *_var_end; \ - HTEntry *_var_next; \ - HTEntry *entry - -/** Macro to iterate over the entries in a hashtable. - * Must be in a scope where HashTable_for_decl() has been used to declare - * variables for it to use. - * The variable 'entry' is iterated over entries in the table. - * The code produced is syntactically a loop, so it must be followed by - * a loop body, typically some statements in braces: - * HashTable_for_each(entry, table){ ...loop body... } - * - * HashTable_for_each() and HashTable_for_decl() cannot be used for nested - * loops as variables will clash. - * - * @note The simplest way to code a direct loop over the entries in a hashtable - * is to use a loop over the buckets, with a nested loop over the entries - * in a bucket. Using this approach in a macro means the macro contains - * an opening brace, and calls to it must be followed by 2 braces! - * To avoid this the code has been restructured so that it is a for loop. - * So that statements could be used in the test expression of the for loop, - * we have used the gcc statement expression extension ({ ... }). - * - * @param entry variable to iterate over the entries - * @param table to iterate over (non-null) - */ -#define HashTable_for_each(entry, table) \ - _var_table = table; \ - _var_bucket = _var_table->buckets; \ - _var_end = _var_bucket + _var_table->buckets_n; \ - for(entry=0, _var_next=0; \ - ({ if(_var_next){ \ - entry = _var_next; \ - _var_next = entry->next; \ - } else { \ - while(_var_bucket < _var_end){ \ - entry = _var_bucket->head; \ - _var_bucket++; \ - if(entry){ \ - _var_next = entry->next; \ - break; \ - } \ - } \ - }; \ - entry; }); \ - entry = _var_next ) - -/** Map a function over the entries in a table. - * Mapping stops when the function returns a non-zero value. - * Uses the gcc statement expression extension ({ ... }). - * - * @param table to map over - * @param fn function to apply to entries - * @param arg first argument to call the function with - * @return 0 if fn always returned 0, first non-zero value otherwise - */ -#define HashTable_map(table, fn, arg) \ - ({ HashTable_for_decl(_var_entry); \ - TableArg _var_arg = arg; \ - int _var_value = 0; \ - HashTable_for_each(_var_entry, table){ \ - if((_var_value = fn(_var_arg, _var_table, _var_entry))) break; \ - } \ - _var_value; }) - -/** Cast x to the type for a key or value in a hash table. - * This avoids compiler warnings when using short integers - * as keys or values (especially on 64-bit platforms). - */ -#define HKEY(x) ((void*)(unsigned long)(x)) - -/** Cast x from the type for a key or value in a hash table. - * to an unsigned long. This avoids compiler warnings when using - * short integers as keys or values (especially on 64-bit platforms). - */ -#define HVAL(x) ((unsigned long)(x)) - -#endif /* !_XEN_LIB_HASH_TABLE_H_ */ diff --git a/tools/lib/iostream.c b/tools/lib/iostream.c deleted file mode 100644 index e9980838f7..0000000000 --- a/tools/lib/iostream.c +++ /dev/null @@ -1,37 +0,0 @@ -#include "iostream.h" -#include "sys_string.h" - -/** Print on a stream, like vfprintf(). - * - * @param stream to print to - * @param format for the print (as fprintf()) - * @param args arguments to print - * @return result code from the print - */ -int IOStream_vprint(IOStream *stream, const char *format, va_list args){ - char buffer[1024]; - int k = sizeof(buffer), n; - - n = vsnprintf(buffer, k, (char*)format, args); - if(n < 0 || n > k ){ - n = k; - } - n = IOStream_write(stream, buffer, n); - return n; -} - -/** Print on a stream, like fprintf(). - * - * @param stream to print to - * @param format for the print (as fprintf()) - * @return result code from the print - */ -int IOStream_print(IOStream *stream, const char *format, ...){ - va_list args; - int result = -1; - - va_start(args, format); - result = IOStream_vprint(stream, format, args); - va_end(args); - return result; -} diff --git a/tools/lib/iostream.h b/tools/lib/iostream.h deleted file mode 100644 index 5dbe14a0b4..0000000000 --- a/tools/lib/iostream.h +++ /dev/null @@ -1,243 +0,0 @@ -#ifndef _XC_LINUX_SAVE_H_ -#define _XC_LINUX_SAVE_H_ - -#include -#include -#include - -#ifdef __KERNEL__ -#include -#else -#include -#endif - -#include "allocate.h" - -/** End of input return value. */ -#define IOSTREAM_EOF -1 - -/** An input/output abstraction. - */ -typedef struct IOStream IOStream; - -/** Record of the functions to use for operations on an - * IOStream implementation. - */ -typedef struct IOMethods { - /** Read function. Called with the user data, buffer to read into - * and number of bytes to read. Must return number of bytes read - * on success, less than zero on error. - */ - int (*read)(IOStream *stream, void *buf, size_t n); - - /** Write function. Called with user data, buffer to write and - * number of bytes to write. Must return number of bytes written on - * success, less than zero otherwise. - */ - int (*write)(IOStream *stream, const void *buf, size_t n); - - int (*flush)(IOStream *s); - - int (*error)(IOStream *s); - - int (*close)(IOStream *s); - - void (*free)(IOStream *s); - - void (*lock)(IOStream *s); - void (*unlock)(IOStream *s); - -} IOMethods; - -/** Abstract i/o object. - */ -struct IOStream { - /** Methods to use to implement operations. */ - const IOMethods *methods; - /** Private state for the implementation. */ - const void *data; - /** Flag indicating whether the stream is closed. */ - int closed; - /** Number of bytes written. */ - int written; - /** Number of bytes read. */ - int read; -}; - - -/** IOStream version of stdin. */ -extern IOStream *iostdin; - -/** IOStream version of stdout, */ -extern IOStream *iostdout; - -/** IOStream version of stderr. */ -extern IOStream *iostderr; - -extern int IOStream_print(IOStream *io, const char *format, ...); -extern int IOStream_vprint(IOStream *io, const char *format, va_list args); - -/** Read from a stream. - * - * @param stream input - * @param buf where to put input - * @param n number of bytes to read - * @return if ok, number of bytes read, otherwise negative error code - */ -static inline int IOStream_read(IOStream *stream, void *buf, size_t n){ - int result = 0; - if(stream->closed) goto exit; - if(!stream->methods || !stream->methods->read){ - result = -EINVAL; - goto exit; - } - result = stream->methods->read(stream, buf, n); - if(result > 0){ - stream->read += result; - } - exit: - return result; -} - -/** Write to a stream. - * - * @param stream input - * @param buf where to put input - * @param n number of bytes to write - * @return if ok, number of bytes read, otherwise negative error code - */ -static inline int IOStream_write(IOStream *stream, const void *buf, size_t n){ - int result = 0; - if(stream->closed) goto exit; - if(!stream->methods || !stream->methods->write){ - result = -EINVAL; - goto exit; - } - result = stream->methods->write(stream, buf, n); - if(result > 0){ - stream->written += result; - } - exit: - return result; -} - -/** Flush the stream. - * - * @param stream stream - * @return 0 on success, IOSTREAM_EOF otherwise - */ -static inline int IOStream_flush(IOStream *stream){ - int result = 0; - if(stream->closed){ - result = IOSTREAM_EOF; - } else if(stream->methods->flush){ - result = stream->methods->flush(stream); - if(result < 0) result = IOSTREAM_EOF; - } - return result; -} - -/** Check whether the stream has an error. - * - * @param stream to check - * @return 1 for error, 0 otherwise - */ -static inline int IOStream_error(IOStream *stream){ - int err = 0; - if(stream->methods && stream->methods->error){ - err = stream->methods->error(stream); - } - return err; -} - -/** Close the stream. - * - * @param stream to close - * @return 1 for error, 0 otherwise - */ -static inline int IOStream_close(IOStream *stream){ - int err = 1; - if(stream->methods && stream->methods->close){ - err = stream->methods->close(stream); - } - return err; -} - -/** Test if the stream has been closed. - * - * @param stream to check - * @return 1 if closed, 0 otherwise - */ -static inline int IOStream_is_closed(IOStream *stream){ - return stream->closed; -} - -/** Free the memory used by the stream. - * - * @param stream to free - */ -static inline void IOStream_free(IOStream *stream){ - if(stream->methods && stream->methods->free){ - stream->methods->free(stream); - } - *stream = (IOStream){}; - deallocate(stream); -} - - -/** Print a character to a stream, like fputc(). - * - * @param stream to print to - * @param c character to print - * @return result code from the print - */ -static inline int IOStream_putc(IOStream *stream, int c){ - int err; - unsigned char b = (unsigned char)c; - err = IOStream_write(stream, &b, 1); - if(err < 1){ - err = IOSTREAM_EOF; - } else { - err = b; - } - return err; -} - -/** Read from a stream, like fgetc(). - * - * @param stream to read from - * @return IOSTREAM_EOF on error, character read otherwise - */ -static inline int IOStream_getc(IOStream *stream){ - int err, rc; - unsigned char b; - - err = IOStream_read(stream, &b, 1); - if(err < 1){ - rc = IOSTREAM_EOF; - } else { - rc = b; - } - return rc; -} - -/** Get number of bytes read. - * - * @param stream to get from - * @return number of bytes read - */ -static inline int IOStream_get_read(IOStream *stream){ - return stream->read; -} - -/** Get number of bytes written. - * - * @param stream to get from - * @return number of bytes written - */ -static inline int IOStream_get_written(IOStream *stream){ - return stream->written; -} - - -#endif /* ! _XC_LINUX_SAVE_H_ */ diff --git a/tools/lib/kernel_stream.c b/tools/lib/kernel_stream.c deleted file mode 100644 index 345b048015..0000000000 --- a/tools/lib/kernel_stream.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (C) 2001 - 2004 Mike Wray - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/** @file - * An IOStream implementation using printk() for output. - * Input is not implemented. - */ -#ifdef __KERNEL__ - -#include -#include -#include -#include -#include -#include -#include - -#include "kernel_stream.h" -#include "allocate.h" - -/** Number of characters in the output buffer. - * The kernel uses 1024 for printk, so that should suffice. - */ -#define BUF_N 1024 - -/** State for a kernel stream. */ -typedef struct KernelData { - /** Stream lock. We need a lock to serialize access to the stream. */ - spinlock_t lock; - /** Saved flags for locking. */ - unsigned long flags; - /** Size of the output buffer. */ - int buf_n; - /** Output buffer. */ - char buf[BUF_N]; -} KernelData; - -static int kernel_write(IOStream *s, const char *msg, int n); -static void kernel_free(IOStream *s); -static void kernel_stream_lock(IOStream *s); -static void kernel_stream_unlock(IOStream *s); - -/** Methods for a kernel stream. Output only. */ -static const IOMethods kernel_methods = { - write: kernel_write, - free: kernel_free, - lock: kernel_stream_lock, - unlock: kernel_stream_unlock, -}; - -/** Shared state for kernel streams. - * All implementations write using printk, so we can use - * shared state and avoid allocating it. - */ -static const KernelData kernel_data = { - lock: SPIN_LOCK_UNLOCKED, - flags: 0, - buf_n: BUF_N, -}; - -/** Stream for kernel printk. */ -static IOStream iokernel = { - methods: &kernel_methods, - data: &kernel_data, -}; - -/** Stream for kernel printk. */ -IOStream *iostdout = &iokernel; - -/** Stream for kernel printk. */ -IOStream *iostdin = &iokernel; - -/** Stream for kernel printk. */ -IOStream *iostderr = &iokernel; - -/** Get an output-only stream implementation using - * printk(). The stream uses static storage, and must not be freed. - * - * @return kernel stream - */ -IOStream get_stream_kernel(void){ - return iokernel; -} - -/** Obtain the lock on the stream state. - * - * @param kdata stream state - */ -static inline void KernelData_lock(KernelData *kdata){ - spin_lock_irqsave(&kdata->lock, kdata->flags); -} - -/** Release the lock on the stream state. - * - * @param kdata stream state - */ -static inline void KernelData_unlock(KernelData *kdata){ - spin_unlock_irqrestore(&kdata->lock, kdata->flags); -} - -/** Get the stream state. - * - * @param s kernel stream - * @return stream state - */ -static inline KernelData *get_kernel_data(IOStream *s){ - return (KernelData*)s->data; -} - -/** Obtain the lock on the stream state. - * - * @param s stream - */ -void kernel_stream_lock(IOStream *s){ - KernelData_lock(get_kernel_data(s)); -} - -/** Release the lock on the stream state. - * - * @param s stream - */ -void kernel_stream_unlock(IOStream *s){ - KernelData_unlock(get_kernel_data(s)); -} - -/** Write to a kernel stream. - * - * @param stream kernel stream - * @param format print format - * @param args print arguments - * @return result of the print - */ -static int kernel_write(IOStream *stream, const char *buf, int n){ - KernelData *kdata = get_kernel_data(stream); - int k; - k = kdata->buf_n - 1; - if(n < k) k = n; - memcpy(kdata->buf, buf, k); - kdata->buf[k] = '\0' - printk(kdata->buf); - return k; -} - -/** Free a kernel stream. - * Frees the internal state of the stream. - * Do not call this unless the stream was dynamically allocated. - * Do not call this on a stream returned from get_stream_kernel(). - * - * @param io stream to free - */ -static void kernel_free(IOStream *io){ - KernelData *kdata; - if(io == &iokernel) return; - kdata = get_kernel_data(io); - zero(kdata, sizeof(*kdata)); - deallocate(kdata); -} -#endif /* __KERNEL__ */ - - - - diff --git a/tools/lib/kernel_stream.h b/tools/lib/kernel_stream.h deleted file mode 100644 index be370f2a45..0000000000 --- a/tools/lib/kernel_stream.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2001 - 2004 Mike Wray - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _XEN_LIB_KERNEL_STREAM_H_ -#define _XEN_LIB_KERNEL_STREAM_H_ - -#ifdef __KERNEL__ -#include "iostream.h" - -extern IOStream get_stream_kernel(void); -#define get_stream_stdout get_stream_kernel - -#endif /* __KERNEL__ */ -#endif /* !_XEN_LIB_KERNEL_STREAM_H_ */ diff --git a/tools/lib/lexis.c b/tools/lib/lexis.c deleted file mode 100644 index 26d2ec4d5b..0000000000 --- a/tools/lib/lexis.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of the - * License, or (at your option) any later version. This library is - * distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/** @file - * Lexical analysis. - */ - -#include "sys_string.h" -#include "lexis.h" -#include - -/** Check if a value lies in a (closed) range. - * - * @param x value to test - * @param lo low end of the range - * @param hi high end of the range - * @return 1 if x is in the interval [lo, hi], 0 otherwise - */ -inline static int in_range(int x, int lo, int hi){ - return (lo <= x) && (x <= hi); -} - -/** Determine if a string is an (unsigned) decimal number. - * - * @param s pointer to characters to test - * @param n length of string - * @return 1 if s is a decimal number, 0 otherwise. - */ -int is_decimal_number(const char *s, int n){ - int i; - if(n <= 0)return 0; - for(i = 0; i < n; i++){ - if(!in_decimal_digit_class(s[i])) return 0; - } - return 1; -} - -/** Determine if a string is a hex number. - * Hex numbers are 0, or start with 0x or 0X followed - * by a non-zero number of hex digits (0-9,a-f,A-F). - * - * @param s pointer to characters to test - * @param n length of string - * @return 1 if s is a hex number, 0 otherwise. - */ -int is_hex_number(const char *s, int n){ - int i; - if(n <= 0) return 0; - if(n == 1){ - return s[0]=='0'; - } - if(n <= 3) return 0; - if(s[0] != '0' || (s[1] != 'x' && s[1] != 'X')) return 0; - for(i = 2; i < n; i++){ - if(!in_hex_digit_class(s[i])) return 0; - } - return 1; -} - -/** Test if a string matches a keyword. - * The comparison is case-insensitive. - * The comparison fails if either argument is null. - * - * @param s string - * @param k keyword - * @return 1 if they match, 0 otherwise - */ -int is_keyword(const char *s, const char *k){ - return s && k && !strcasecmp(s, k); -} - -/** Test if a string matches a character. - * - * @param s string - * @param c character (non-null) - * @return 1 if s contains exactly c, 0 otherwise - */ -int is_keychar(const char *s, char c){ - return c && (s[0] == c) && !s[1]; -} diff --git a/tools/lib/lexis.h b/tools/lib/lexis.h deleted file mode 100644 index 7d8fe7bc63..0000000000 --- a/tools/lib/lexis.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of the - * License, or (at your option) any later version. This library is - * distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _SP_LEXIS_H_ -#define _SP_LEXIS_H_ - -#include "sys_string.h" -#include "sys_ctype.h" - -/** @file - * Lexical analysis. - */ - -/** Class of characters treated as space. */ -#define space_class ((char []){ '\n', '\r', '\t', ' ', '\f' , 0 }) - -/** Class of separator characters. */ -#define sep_class "{}()<>[]@!;" - -#define comment_class "#" - -/** Determine if a character is in a given class. - * - * @param c character to test - * @param s null-terminated string of characters in the class - * @return 1 if c is in the class, 0 otherwise. - */ -static inline int in_class(int c, const char *s){ - return s && (strchr(s, c) != 0); -} - -/** Determine if a character is in the space class. - * - * @param c character to test - * @return 1 if c is in the class, 0 otherwise. - */ -static inline int in_space_class(int c){ - return in_class(c, space_class); -} - -static inline int in_comment_class(int c){ - return in_class(c, comment_class); -} - -/** Determine if a character is in the separator class. - * Separator characters terminate tokens, and do not need space - * to separate them. - * - * @param c character to test - * @return 1 if c is in the class, 0 otherwise. - */ -static inline int in_sep_class(int c){ - return in_class(c, sep_class); -} - -/** Determine if a character is in the alpha class. - * - * @param c character to test - * @return 1 if c is in the class, 0 otherwise. - */ -static inline int in_alpha_class(int c){ - return isalpha(c); -} - -/** Determine if a character is in the octal digit class. - * - * @param c character to test - * @return 1 if c is in the class, 0 otherwise. - */ -static inline int in_octal_digit_class(int c){ - return '0' <= c && c <= '7'; -} - -/** Determine if a character is in the decimal digit class. - * - * @param c character to test - * @return 1 if c is in the class, 0 otherwise. - */ -static inline int in_decimal_digit_class(int c){ - return isdigit(c); -} - -/** Determine if a character is in the hex digit class. - * - * @param c character to test - * @return 1 if c is in the class, 0 otherwise. - */ -static inline int in_hex_digit_class(int c){ - return isdigit(c) || in_class(c, "abcdefABCDEF"); -} - - -static inline int in_string_quote_class(int c){ - return in_class(c, "'\""); -} - -static inline int in_printable_class(int c){ - return ('A' <= c && c <= 'Z') - || ('a' <= c && c <= 'z') - || ('0' <= c && c <= '9') - || in_class(c, "!$%&*+,-./:;<=>?@^_`{|}~"); -} - -extern int is_decimal_number(const char *s, int n); -extern int is_hex_number(const char *s, int n); -extern int is_keyword(const char *s, const char *k); -extern int is_keychar(const char *s, char c); - -#endif /* !_SP_LEXIS_H_ */ diff --git a/tools/lib/lzi_stream.c b/tools/lib/lzi_stream.c deleted file mode 100644 index 0f09734201..0000000000 --- a/tools/lib/lzi_stream.c +++ /dev/null @@ -1,590 +0,0 @@ -/* $Id: lzi_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $ */ -#define __FILE_ID_INFO "$Id: lzi_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $" -#include -static char __rcsid[] __attribute__((unused)) = WHAT_ID __FILE_ID_INFO; -/* - * Copyright (C) 2003 Hewlett-Packard Company. - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/** @file - * An IOStream implementation using LZI to provide compression and decompression. - * This is designed to provide compression without output latency. - * Flushing an LZI stream flushes all pending data to the underlying stream. - * This is essential for stream-based (e.g. networked) applications. - * - * A compressed data stream is a sequence of blocks. - * Each block is the block size followed by the compressed data. - * The last block has size zero. - * Sizes are 4-byte unsigned in network order. - * - * This format allows compressed data to be read from a stream without reading - * past the logical end of compressed data. - * - * @author Mike Wray - */ -#ifndef __KERNEL__ - -#include -#include -#include -#include - -#include "zlib.h" - -#include "allocate.h" -#include "lzi_stream.h" -#include "file_stream.h" -#include "marshal.h" - -#define dprintf(fmt, args...) fprintf(stdout, "[DEBUG] LZI>%s" fmt, __FUNCTION__, ##args) -#define wprintf(fmt, args...) fprintf(stderr, "[WARN] LZI>%s" fmt, __FUNCTION__, ##args) -#define iprintf(fmt, args...) fprintf(stdout, "[INFO] LZI>%s" fmt, __FUNCTION__, ##args) -#define eprintf(fmt, args...) fprintf(stderr, "[ERROR] LZI>%s" fmt, __FUNCTION__, ##args) - -static int lzi_read(IOStream *s, void *buf, size_t size, size_t count); -static int lzi_write(IOStream *s, const void *buf, size_t size, size_t count); -static int lzi_print(IOStream *s, const char *msg, va_list args); -static int lzi_getc(IOStream *s); -static int lzi_error(IOStream *s); -static int lzi_close(IOStream *s); -static void lzi_free(IOStream *s); -static int lzi_flush(IOStream *s); - -enum { - LZI_WRITE = 1, - LZI_READ = 2, -}; - -/** Methods used by a gzFile* IOStream. */ -static const IOMethods lzi_methods = { - read: lzi_read, - write: lzi_write, - print: lzi_print, - getc: lzi_getc, - error: lzi_error, - close: lzi_close, - free: lzi_free, - flush: lzi_flush, -}; - -#define BUFFER_SIZE (512 * 1024) - -typedef struct LZIState { - z_stream zstream; - void *inbuf; - uint32_t inbuf_size; - void *outbuf; - uint32_t outbuf_size; - /** Underlying stream for I/O. */ - IOStream *io; - /** Flags. */ - int flags; - /** Error indicator. */ - int error; - int eof; - int plain_bytes; - int comp_bytes; - int zstream_initialized; - int flushed; -} LZIState; - -static inline int LZIState_writeable(LZIState *s){ - return (s->flags & LZI_WRITE) != 0; -} - -static inline int LZIState_readable(LZIState *s){ - return (s->flags & LZI_READ) != 0; -} - -void LZIState_free(LZIState *z){ - if(!z) return; - if(z->zstream_initialized){ - if(LZIState_writeable(z)){ - deflateEnd(&z->zstream); - } else if(LZIState_readable(z)){ - inflateEnd(&z->zstream); - } - } - deallocate(z->inbuf); - deallocate(z->outbuf); - deallocate(z); -} - -static int mode_flags(const char *mode, int *flags){ - int err = 0; - int r=0, w=0; - if(!mode){ - err = -EINVAL; - goto exit; - } - for(; *mode; mode++){ - if(*mode == 'w') w = 1; - if(*mode == 'r') r = 1; - } - if(r + w != 1){ - err = -EINVAL; - goto exit; - } - if(r) *flags |= LZI_READ; - if(w) *flags |= LZI_WRITE; - exit: - return err; -} - -/** Get the stream state. - * - * @param s lzi stream - * @return stream state. - */ -static inline LZIState * lzi_state(IOStream *io){ - return io->data; -} - -IOStream *lzi_stream_io(IOStream *io){ - LZIState *s = lzi_state(io); - return s->io; -} - -static inline void set_error(LZIState *s, int err){ - if(err < 0 && !s->error){ - s->error = err; - } -} - -static int zerror(LZIState *s, int err){ - if(err){ - //dprintf("> err=%d\n", err); - if(err < 0) set_error(s, -EIO); - } - return s->error; -} - -int lzi_stream_plain_bytes(IOStream *io){ - LZIState *s = lzi_state(io); - return s->plain_bytes; -} - -int lzi_stream_comp_bytes(IOStream *io){ - LZIState *s = lzi_state(io); - return s->comp_bytes; -} - -float lzi_stream_ratio(IOStream *io){ - LZIState *s = lzi_state(io); - float ratio = 0.0; - if(s->comp_bytes){ - ratio = ((float) s->comp_bytes)/((float) s->plain_bytes); - } - return ratio; -} - -static int alloc(void **p, int n){ - *p = allocate(n); - return (p ? 0 : -ENOMEM); -} - -LZIState * LZIState_new(IOStream *io, int flags){ - int err = -ENOMEM; - int zlevel = Z_BEST_SPEED; // Level 1 compression - fastest. - int zstrategy = Z_DEFAULT_STRATEGY; - int zwindow = MAX_WBITS; - int zmemory = 8; - LZIState *z = ALLOCATE(LZIState); - - //dprintf(">\n"); - if(!z) goto exit; - z->io = io; - z->flags = flags; - - if(LZIState_writeable(z)){ - z->outbuf_size = BUFFER_SIZE; - /* windowBits is passed < 0 to suppress zlib header */ - err = deflateInit2(&z->zstream, zlevel, Z_DEFLATED, -zwindow, zmemory, zstrategy); - if (err != Z_OK) goto exit; - z->zstream_initialized = 1; - err = alloc(&z->outbuf, z->outbuf_size); - if(err) goto exit; - z->zstream.next_out = z->outbuf; - z->zstream.avail_out = z->outbuf_size; - } else { - z->inbuf_size = BUFFER_SIZE; - err = alloc(&z->inbuf, z->inbuf_size); - if(err) goto exit; - ///z->zstream.next_in = z->inbuf; - - /* windowBits is passed < 0 to tell that there is no zlib header. - * Note that in this case inflate *requires* an extra "dummy" byte - * after the compressed stream in order to complete decompression and - * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are - * present after the compressed stream. - */ - err = inflateInit2(&z->zstream, -zwindow); - if(err != Z_OK) goto exit; - z->zstream_initialized = 1; - } - - exit: - if(err){ - LZIState_free(z); - z = NULL; - } - //dprintf("< z=%p\n", z); - return z; -} - -int read_block(LZIState *s){ - int err = 0, k = 0; - //dprintf(">\n"); - if(s->eof) goto exit; - err = unmarshal_uint32(s->io, &k); - if(err) goto exit; - if(k > s->inbuf_size){ - err = -EINVAL; - goto exit; - } - if(k){ - err = unmarshal_bytes(s->io, s->inbuf, k); - if(err) goto exit; - } else { - s->eof = 1; - } - s->zstream.avail_in = k; - s->zstream.next_in = s->inbuf; - s->comp_bytes += 4; - s->comp_bytes += k; - exit: - //dprintf("< err=%d\n", err); - return err; -} - -int write_block(LZIState *s){ - int err = 0; - int k = ((char*)s->zstream.next_out) - ((char*)s->outbuf); - int k2 = s->outbuf_size - s->zstream.avail_out; - //dprintf("> k=%d k2=%d\n", k, k2); - if(!k) goto exit; - err = marshal_uint32(s->io, k); - if(err) goto exit; - err = marshal_bytes(s->io, s->outbuf, k); - if(err) goto exit; - s->zstream.next_out = s->outbuf; - s->zstream.avail_out = s->outbuf_size; - s->comp_bytes += 4; - s->comp_bytes += k; - exit: - //dprintf("< err=%d\n", err); - return err; -} - -int write_terminator(LZIState *s){ - int err = 0; - char c = 0; - err = marshal_uint32(s->io, 1); - if(err) goto exit; - err = marshal_bytes(s->io, &c, 1); - if(err) goto exit; - err = marshal_uint32(s->io, 0); - if(err) goto exit; - s->comp_bytes += 9; - exit: - return err; -} - -/** Write to the underlying stream using fwrite(); - * - * @param io destination - * @param buf data - * @param size size of data elements - * @param count number of data elements to write - * @return number of data elements written - */ -static int lzi_write(IOStream *io, const void *buf, size_t size, size_t count){ - int err = 0; - int n = size * count; - LZIState *s = lzi_state(io); - - //dprintf("> buf=%p size=%d count=%d n=%d\n", buf, size, count, n); - if(!LZIState_writeable(s)){ - err = -EINVAL; - goto exit; - } - s->flushed = 0; - s->zstream.next_in = (void*)buf; - s->zstream.avail_in = n; - while(s->zstream.avail_in){ - if(s->zstream.avail_out == 0){ - err = write_block(s); - if(err) goto exit; - } - //dprintf("> 1 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out); - //dprintf("> 1 deflate next_in=%p next_out=%p\n", s->zstream.next_in, s->zstream.next_out); - err = zerror(s, deflate(&s->zstream, Z_NO_FLUSH)); - //dprintf("> 2 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out); - //dprintf("> 2 deflate next_in=%p next_out=%p\n", s->zstream.next_in, s->zstream.next_out); - if(err) goto exit; - } - err = n; - s->plain_bytes += n; - if(size != 1) err /= size; - exit: - //dprintf("< err=%d\n", err); - return err; -} - - -/** Read from the underlying stream. - * - * @param io input - * @param buf where to put input - * @param size size of data elements - * @param count number of data elements to read - * @return number of data elements read - */ -static int lzi_read(IOStream *io, void *buf, size_t size, size_t count){ - int err, zerr; - int n = size * count; - LZIState *s = lzi_state(io); - - //dprintf("> size=%d count=%d n=%d\n", size, count, n); - if(!LZIState_readable(s)){ - err = -EINVAL; - goto exit; - } - s->zstream.next_out = buf; - s->zstream.avail_out = n; - while(s->zstream.avail_out){ - if(s->zstream.avail_in == 0){ - err = read_block(s); - } - //dprintf("> 1 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out); - zerr = inflate(&s->zstream, Z_NO_FLUSH); - //dprintf("> 2 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out); - if(zerr == Z_STREAM_END) break; - //dprintf("> zerr=%d\n", zerr); - err = zerror(s, zerr); - if(err) goto exit; - } - err = n - s->zstream.avail_out; - s->plain_bytes += err; - if(size != 1) err /= size; - exit: - set_error(s, err); - //dprintf("< err=%d\n", err); - return err; -} - -/** Print to the underlying stream. - * Returns 0 if the formatted output is too big for the internal buffer. - * - * @param io lzi stream - * @param msg format to use - * @param args arguments - * @return result of the print - */ -static int lzi_print(IOStream *io, const char *msg, va_list args){ - char buf[1024]; - int buf_n = sizeof(buf); - int n; - LZIState *s = lzi_state(io); - if(!LZIState_writeable(s)){ - n = -EINVAL; - goto exit; - } - n = vsnprintf(buf, buf_n, (char*)msg, args); - if(n < 0) goto exit; - if(n > buf_n){ - n = 0; - } else { - n = lzi_write(io, buf, 1, n); - } - exit: - return n; -} - -/** Read a character from the underlying stream - * - * @param io lzi stream - * @return character read, IOSTREAM_EOF on end of file (or error) - */ -static int lzi_getc(IOStream *io){ - int err; - char c; - err = lzi_read(io, &c, 1, 1); - if(err < 1) c = EOF; - err = (c==EOF ? IOSTREAM_EOF : c); - return err; -} - -static int flush_output(LZIState *s, int mode){ - int err = 0, zerr; - int done = 0; - int avail_out_old; - int count = 10; - - //dprintf("> avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out); - if(s->flushed == 1 + mode) goto exit; - //s->zstream.avail_in = 0; /* should be zero already anyway */ - for(;;){ - // Write any available output. - if(done || s->zstream.avail_out == 0){ - err = write_block(s); - if(err) goto exit; - if(done) break; - } - //dprintf("> 1 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out); - avail_out_old = s->zstream.avail_out; - zerr = deflate(&s->zstream, mode); - err = zerror(s, zerr); - //dprintf("> 2 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out); - //dprintf("> deflate=%d\n", err); - //done = (s->zstream.avail_out != 0); - //done = (s->zstream.avail_in == 0) && (s->zstream.avail_out == avail_out_old); - if(0 && mode == Z_FINISH){ - done = (zerr == Z_STREAM_END); - } else { - done = (s->zstream.avail_in == 0) - //&& (s->zstream.avail_out == avail_out_old) - && (s->zstream.avail_out != 0); - } - } - s->flushed = 1 + mode; - exit: - //dprintf("< err=%d\n", err); - return err; -} - -/** Flush any pending input to the underlying stream. - * - * @param s lzi stream - * @return 0 on success, error code otherwise - */ -static int lzi_flush(IOStream *io){ - int err = 0; - LZIState *s = lzi_state(io); - //dprintf(">\n"); - if(!LZIState_writeable(s)){ - err = -EINVAL; - goto exit; - } - err = flush_output(s, Z_SYNC_FLUSH); - if(err) goto exit; - err = IOStream_flush(s->io); - exit: - set_error(s, err); - //dprintf("< err=%d\n", err); - return (err < 0 ? err : 0); -} - -/** Check if a stream has an error. - * - * @param s lzi stream - * @return code if has an error, 0 otherwise - */ -static int lzi_error(IOStream *s){ - int err = 0; - LZIState *state = lzi_state(s); - err = state->error; - if(err) goto exit; - err = IOStream_error(state->io); - exit: - return err; -} - -/** Close an lzi stream. - * - * @param s lzi stream to close - * @return result of the close - */ -static int lzi_close(IOStream *io){ - int err = 0; - LZIState *s = lzi_state(io); - if(LZIState_writeable(s)){ - err = flush_output(s, Z_FINISH); - if(err) goto exit; - err = write_terminator(s); - if(err) goto exit; - err = IOStream_flush(s->io); - } - exit: - err = IOStream_close(s->io); - set_error(s, err); - return err; -} - -/** Free an lzi stream. - * - * @param s lzi stream - */ -static void lzi_free(IOStream *s){ - LZIState *state = lzi_state(s); - IOStream_free(state->io); - LZIState_free(state); - s->data = NULL; -} - -/** Create an lzi stream for an IOStream. - * - * @param io stream to wrap - * @return new IOStream using f for i/o - */ -IOStream *lzi_stream_new(IOStream *io, const char *mode){ - int err = -ENOMEM; - int flags = 0; - IOStream *zio = NULL; - LZIState *state = NULL; - - zio = ALLOCATE(IOStream); - if(!zio) goto exit; - err = mode_flags(mode, &flags); - if(err) goto exit; - state = LZIState_new(io, flags); - if(!state) goto exit; - err = 0; - zio->data = state; - zio->methods = &lzi_methods; - exit: - if(err){ - if(state) LZIState_free(state); - if(zio) deallocate(zio); - zio = NULL; - } - return zio; -} - -/** IOStream version of fdopen(). - * - * @param fd file descriptor - * @param flags giving the mode to open in (as for fdopen()) - * @return new stream for the open file, or NULL if failed - */ -IOStream *lzi_stream_fdopen(int fd, const char *mode){ - int err = -ENOMEM; - IOStream *io = NULL, *zio = NULL; - io = file_stream_fdopen(fd, mode); - if(!io) goto exit; - zio = lzi_stream_new(io, mode); - if(!io) goto exit; - err = 0; - exit: - if(err){ - IOStream_free(io); - IOStream_free(zio); - zio = NULL; - } - return zio; -} -#endif diff --git a/tools/lib/lzi_stream.h b/tools/lib/lzi_stream.h deleted file mode 100644 index 0ad4f8db8e..0000000000 --- a/tools/lib/lzi_stream.h +++ /dev/null @@ -1,36 +0,0 @@ -#/* $Id: lzi_stream.h,v 1.3 2003/09/30 15:22:53 mjw Exp $ */ -/* - * Copyright (C) 2003 Hewlett-Packard Company. - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _SP_LZI_STREAM_H_ -#define _SP_LZI_STREAM_H_ - -#ifndef __KERNEL__ -#include "iostream.h" - -extern IOStream *lzi_stream_new(IOStream *io, const char *mode); -extern IOStream *lzi_stream_fopen(const char *file, const char *mode); -extern IOStream *lzi_stream_fdopen(int fd, const char *mode); -extern IOStream *lzi_stream_io(IOStream *zio); - -extern int lzi_stream_plain_bytes(IOStream *io); -extern int lzi_stream_comp_bytes(IOStream *io); -extern float lzi_stream_ratio(IOStream *io); - -#endif -#endif /* !_SP_FILE_STREAM_H_ */ diff --git a/tools/lib/lzo_stream.c b/tools/lib/lzo_stream.c deleted file mode 100644 index bf7c348471..0000000000 --- a/tools/lib/lzo_stream.c +++ /dev/null @@ -1,596 +0,0 @@ -/* $Id: lzo_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $ */ -#define __FILE_ID_INFO "$Id: lzo_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $" -#include -static char __rcsid[] __attribute__((unused)) = WHAT_ID __FILE_ID_INFO; -/* - * Copyright (C) 2003 Hewlett-Packard Company. - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/** @file - * An IOStream implementation using LZO to provide compression and decompression. - * This is designed to provide reasonable compression without output latency. - * Flushing an LZO stream flushes all pending data to the underlying stream. - * This is essential for stream-based (e.g. networked) applications. - * - * A compressed data stream is a sequence of blocks. - * Each block except the last is the plain data size followed by the compressed data size - * and the compressed data. The last block has plain data size zero and omits the rest. - * Sizes are 4-byte unsigned in network order. If the compressed size is smaller than - * the plain size the block data is compressed, otherwise it is plain (uncompressed). - * - * This format allows compressed data to be read from a stream without reading - * past the logical end of compressed data. - * - * @author Mike Wray - */ -#ifndef __KERNEL__ - -#include -#include -#include -#include - -#include "lzo1x.h" - -#include "allocate.h" -#include "lzo_stream.h" -#include "file_stream.h" -#include "marshal.h" - -#define dprintf(fmt, args...) fprintf(stdout, "[DEBUG] LZO>%s" fmt, __FUNCTION__, ##args) -#define wprintf(fmt, args...) fprintf(stderr, "[WARN] LZO>%s" fmt, __FUNCTION__, ##args) -#define iprintf(fmt, args...) fprintf(stdout, "[INFO] LZO>%s" fmt, __FUNCTION__, ##args) -#define eprintf(fmt, args...) fprintf(stderr, "[ERROR] LZO>%s" fmt, __FUNCTION__, ##args) - -static int lzo_read(IOStream *s, void *buf, size_t size, size_t count); -static int lzo_write(IOStream *s, const void *buf, size_t size, size_t count); -static int lzo_print(IOStream *s, const char *msg, va_list args); -static int lzo_getc(IOStream *s); -static int lzo_error(IOStream *s); -static int lzo_close(IOStream *s); -static void lzo_free(IOStream *s); -static int lzo_flush(IOStream *s); - -enum { - LZO_WRITE = 1, - LZO_READ = 2, -}; - -/** Methods used by a gzFile* IOStream. */ -static const IOMethods lzo_methods = { - read: lzo_read, - write: lzo_write, - print: lzo_print, - getc: lzo_getc, - error: lzo_error, - close: lzo_close, - free: lzo_free, - flush: lzo_flush, -}; - -//#define PLAIN_SIZE (64 * 1024) -//#define PLAIN_SIZE (128 * 1024) -#define PLAIN_SIZE (512 * 1024) - -//#define NOCOMPRESS - -typedef struct LZOState { - /** Flags. */ - int flags; - /** Error indicator. */ - int error; - /** Underlying stream for I/O. */ - IOStream *io; - /** Working memory (only needed for compression, not decompression). */ - lzo_byte *memory; - /** Buffer for plain (uncompressed) data. */ - lzo_byte *plain; - /** Size of the plain buffer. */ - lzo_uint plain_size; - /** Pointer into the plain buffer. */ - lzo_byte *plain_ptr; - /** Number of bytes of plain data available. */ - lzo_uint plain_n; - /** Buffer for compressed data. */ - lzo_byte *comp; - /** Size of the compressed buffer. */ - lzo_uint comp_size; - - int plain_bytes; - int comp_bytes; -} LZOState; - -void LZOState_free(LZOState *z){ - if(!z) return; - deallocate(z->memory); - deallocate(z->plain); - deallocate(z->comp); - deallocate(z); -} - -/** Maximum size of compressed data for the given plain data size. - * - * @param plain_size size of plain data - * @return maximum size of compressed data - */ -static int comp_size(int plain_size){ - return plain_size + (plain_size / 64) + 16 + 3; -} - -static int mode_flags(const char *mode, int *flags){ - int err = 0; - int r=0, w=0; - if(!mode){ - err = -EINVAL; - goto exit; - } - for(; *mode; mode++){ - if(*mode == 'w') w = 1; - if(*mode == 'r') r = 1; - } - if(r + w != 1){ - err = -EINVAL; - goto exit; - } - if(r) *flags |= LZO_READ; - if(w) *flags |= LZO_WRITE; - exit: - return err; -} - -/** Get the stream state. - * - * @param s lzo stream - * @return stream state. - */ -static inline LZOState * lzo_state(IOStream *s){ - return s->data; -} - -IOStream *lzo_stream_io(IOStream *s){ - LZOState *state = lzo_state(s); - return state->io; -} - -static inline void set_error(LZOState *state, int err){ - if(err < 0 && !state->error){ - state->error = err; - } -} - -int lzo_stream_plain_bytes(IOStream *s){ - LZOState *state = lzo_state(s); - return state->plain_bytes; -} - -int lzo_stream_comp_bytes(IOStream *s){ - LZOState *state = lzo_state(s); - return state->comp_bytes; -} - -float lzo_stream_ratio(IOStream *s){ - LZOState *state = lzo_state(s); - float ratio = 0.0; - if(state->comp_bytes){ - ratio = ((float) state->comp_bytes)/((float) state->plain_bytes); - } - return ratio; -} - -static inline int LZOState_writeable(LZOState *state){ - return (state->flags & LZO_WRITE) != 0; -} - -static inline int LZOState_readable(LZOState *state){ - return (state->flags & LZO_READ) != 0; -} - -LZOState * LZOState_new(IOStream *io, int flags){ - int err = -ENOMEM; - LZOState *z = ALLOCATE(LZOState); - //dprintf(">\n"); - if(!z) goto exit; - z->io = io; - z->flags = flags; - if(LZOState_writeable(z)){ - z->memory = allocate(LZO1X_1_MEM_COMPRESS); - if(!z->memory) goto exit; - } - z->plain_size = PLAIN_SIZE; - z->plain = allocate(z->plain_size); - if(!z->plain) goto exit; - z->plain_ptr = z->plain; - z->comp_size = comp_size(z->plain_size); - z->comp = allocate(z->comp_size); - if(!z->comp) goto exit; - err = 0; - exit: - if(err){ - LZOState_free(z); - z = NULL; - } - //dprintf("< z=%p\n", z); - return z; -} - -static int lzo_compress(LZOState *state){ - int err = 0; - int k, comp_n; - //dprintf(">\n"); - //dprintf(">plain=%p plain_n=%d comp=%p memory=%p\n", state->plain, state->plain_n, state->comp, state->memory); - // Compress the plain buffer. - err = lzo1x_1_compress(state->plain, state->plain_n, - state->comp, &comp_n, - state->memory); - //dprintf("> err=%d plain_n=%d comp_n=%d\n", err, state->plain_n, comp_n); - // Write plain size, compressed size. - err = marshal_uint32(state->io, state->plain_n); - if(err) goto exit; - err = marshal_uint32(state->io, comp_n); - if(err) goto exit; - //dprintf("> write data...\n"); - // Write the smaller of the compressed and plain data. - if(state->plain_n < comp_n){ - k = state->plain_n; - err = marshal_bytes(state->io, state->plain, state->plain_n); - } else { - k = comp_n; - err = marshal_bytes(state->io, state->comp, comp_n); - } - if(err) goto exit; - // Total output bytes. - k+= 8; - //dprintf("> wrote %d bytes\n", k); - state->plain_bytes += state->plain_n; - state->comp_bytes += k; - //dprintf("> plain=%d, comp=%d, ratio=%3.2f\n", - // state->plain_bytes, state->comp_bytes, - // ((float)state->comp_bytes)/((float)state->plain_bytes)); - // Reset the plain buffer. - state->plain_ptr = state->plain; - state->plain_n = 0; - err = k; - exit: - //dprintf("< err=%d\n", err); - return err; -} - -static int lzo_decompress(LZOState *state){ - int plain_n, comp_n; - int err, k; - //dprintf(">\n"); - err = unmarshal_uint32(state->io, &plain_n); - //dprintf("> err=%d plain_n=%d\n", err, plain_n); - if(err) goto exit; - state->comp_bytes += 4; - if(plain_n == 0) goto exit; - err = unmarshal_uint32(state->io, &comp_n); - //dprintf("> err=%d comp_n=%d\n", err, comp_n); - if(err) goto exit; - state->comp_bytes += 4; - if(plain_n > state->plain_size){ - err = -EINVAL; - goto exit; - } - if(comp_n > plain_n){ - //dprintf("> reading plain data %d...\n", plain_n); - k = plain_n; - err = unmarshal_bytes(state->io, state->plain, plain_n); - state->plain_n = plain_n; - } else { - //dprintf("> reading comp data %d...\n", comp_n); - k = comp_n; - err = unmarshal_bytes(state->io, state->comp, comp_n); - //dprintf("> decompress comp_n=%d\n", comp_n); - err = lzo1x_decompress(state->comp, comp_n, - state->plain, &state->plain_n, - state->memory); - //dprintf("> err=%d plain=%d state->plain_n=%d\n", err, plain_n, state->plain_n); - if(err != LZO_E_OK || state->plain_n != plain_n){ - // Bad. Corrupted input. - err = -EINVAL; - eprintf("> Corrupted!\n"); - goto exit; - } - } - state->comp_bytes += k; - state->plain_bytes += state->plain_n; - state->plain_ptr = state->plain; - err = k; - exit: - //dprintf("< err=%d\n", err); - return err; -} - -/** Write to the underlying stream using fwrite(); - * - * @param stream destination - * @param buf data - * @param size size of data elements - * @param count number of data elements to write - * @return number of data elements written - */ -static int lzo_write(IOStream *s, const void *buf, size_t size, size_t count){ - int err = 0; - int n = size * count; // Total number of bytes to write. - int chunk; // Size of chunk to write. - int remaining; // Number of bytes remaining to write. - int space; // Amount of space left in plain buffer. - LZOState *state = lzo_state(s); -#ifdef NOCOMPRESS - //dprintf("> buf=%p size=%d count=%d\n", buf, size, count); - err = IOStream_write(state->io, buf, size, count); - //dprintf("< err=%d\n", err); -#else - //dprintf("> buf=%p size=%d count=%d n=%d\n", buf, size, count, n); - remaining = n; - space = state->plain_size - state->plain_n; - //dprintf("> plain=%p plain_ptr=%p plain_n=%d space=%d\n", - // state->plain, state->plain_ptr, state->plain_n, space); - while(remaining){ - chunk = remaining; - if(chunk > space) chunk = space; - //dprintf("> memcpy %p %p %d\n", state->plain_ptr, buf, chunk); - memcpy(state->plain_ptr, buf, chunk); - remaining -= chunk; - space -= chunk; - state->plain_ptr += chunk; - state->plain_n += chunk; - if(space == 0){ - // Input buffer is full. Compress and write it. - err = lzo_compress(state); - if(err < 0) goto exit; - space = state->plain_size - state->plain_n; - } - } - err = (size > 1 ? n / size : n); - exit: - set_error(state, err); -#endif - return err; -} - - -/** Read from the underlying stream. - * - * @param stream input - * @param buf where to put input - * @param size size of data elements - * @param count number of data elements to read - * @return number of data elements read - */ -static int lzo_read(IOStream *s, void *buf, size_t size, size_t count){ - int err = 0; - int k = 0; // Number of (plain) bytes read. - int remaining = size * count; // Number of bytes remaining to read. - int chunk; // Size of chunk to read. - LZOState *state = lzo_state(s); -#ifdef NOCOMPRESS - //dprintf("> buf=%p size=%d count=%d\n", buf, size, count); - err = IOStream_read(state->io, buf, size, count); - //dprintf("< err=%d\n", err); -#else - if(!(state->flags & LZO_READ)){ - err = -EINVAL; - goto exit; - } - while(remaining){ - if(state->plain_n == 0){ - // No more plain input, decompress some more. - err = lzo_decompress(state); - if(err < 0) goto exit; - // Stop reading if there is no more input. - if(err == 0 || state->plain_n == 0) break; - } - chunk = remaining; - if(chunk > state->plain_n) chunk = state->plain_n; - memcpy(buf, state->plain_ptr, chunk); - k += chunk; - buf += chunk; - state->plain_ptr += chunk; - state->plain_n -= chunk; - remaining -= chunk; - } - err = k; - exit: - set_error(state, err); -#endif - return err; -} - -/** Print to the underlying stream. - * Returns 0 if the formatted output is too big for the internal buffer. - * - * @param s lzo stream - * @param msg format to use - * @param args arguments - * @return result of the print - */ -static int lzo_print(IOStream *s, const char *msg, va_list args){ - char buf[1024]; - int buf_n = sizeof(buf); - int n; - LZOState *state = lzo_state(s); - if(!LZOState_writeable(state)){ - n = -EINVAL; - goto exit; - } - n = vsnprintf(buf, buf_n, (char*)msg, args); - if(n < 0) goto exit; - if(n > buf_n){ - n = 0; - } else { - n = lzo_write(s, buf, 1, n); - } - exit: - return n; -} - -/** Read a character from the underlying stream - * - * @param s lzo stream - * @return character read, IOSTREAM_EOF on end of file (or error) - */ -static int lzo_getc(IOStream *s){ - int err; - char c; - err = lzo_read(s, &c, 1, 1); - if(err < 1) c = EOF; - err = (c==EOF ? IOSTREAM_EOF : c); - return err; -} - -/** Flush any pending input to the underlying stream. - * - * @param s lzo stream - * @return 0 on success, error code otherwise - */ -static int lzo_flush(IOStream *s){ - int err = 0; - LZOState *state = lzo_state(s); - //dprintf(">\n"); -#ifdef NOCOMPRESS - err = IOStream_flush(state->io); -#else - if(!LZOState_writeable(state)){ - err = -EINVAL; - goto exit; - } - if(state->plain_n){ - err = lzo_compress(state); - if(err < 0) goto exit; - } - err = IOStream_flush(state->io); - exit: - set_error(state, err); -#endif - //dprintf("< err=%d\n", err); - return (err < 0 ? err : 0); -} - -/** Check if a stream has an error. - * - * @param s lzo stream - * @return code if has an error, 0 otherwise - */ -static int lzo_error(IOStream *s){ - int err = 0; - LZOState *state = lzo_state(s); - err = state->error; - if(err) goto exit; - err = IOStream_error(state->io); - exit: - return err; -} - -int lzo_stream_finish(IOStream *s){ - int err = 0; - LZOState *state = lzo_state(s); - if(!LZOState_writeable(state)){ - err = -EINVAL; - goto exit; - } - err = lzo_flush(s); - if(err < 0) goto exit; - err = marshal_int32(state->io, 0); - exit: - return err; -} - -/** Close an lzo stream. - * - * @param s lzo stream to close - * @return result of the close - */ -static int lzo_close(IOStream *s){ - int err = 0; - LZOState *state = lzo_state(s); -#ifdef NOCOMPRESS - err = IOStream_close(state->io); -#else - if(LZOState_writeable(state)){ - err = lzo_stream_finish(s); - } - err = IOStream_close(state->io); - set_error(state, err); -#endif - return err; -} - -/** Free an lzo stream. - * - * @param s lzo stream - */ -static void lzo_free(IOStream *s){ - LZOState *state = lzo_state(s); - IOStream_free(state->io); - LZOState_free(state); - s->data = NULL; -} - -/** Create an lzo stream for an IOStream. - * - * @param io stream to wrap - * @return new IOStream using f for i/o - */ -IOStream *lzo_stream_new(IOStream *io, const char *mode){ - int err = -ENOMEM; - int flags = 0; - IOStream *zio = NULL; - LZOState *state = NULL; - - zio = ALLOCATE(IOStream); - if(!zio) goto exit; - err = mode_flags(mode, &flags); - if(err) goto exit; - state = LZOState_new(io, flags); - if(!state) goto exit; - err = 0; - zio->data = state; - zio->methods = &lzo_methods; - exit: - if(err){ - if(state) LZOState_free(state); - if(zio) deallocate(zio); - zio = NULL; - } - return zio; -} - -/** IOStream version of fdopen(). - * - * @param fd file descriptor - * @param flags giving the mode to open in (as for fdopen()) - * @return new stream for the open file, or NULL if failed - */ -IOStream *lzo_stream_fdopen(int fd, const char *mode){ - int err = -ENOMEM; - IOStream *io = NULL, *zio = NULL; - io = file_stream_fdopen(fd, mode); - if(!io) goto exit; - zio = lzo_stream_new(io, mode); - if(!io) goto exit; - err = 0; - exit: - if(err){ - IOStream_free(io); - IOStream_free(zio); - zio = NULL; - } - return zio; -} -#endif diff --git a/tools/lib/lzo_stream.h b/tools/lib/lzo_stream.h deleted file mode 100644 index 493da7b1ad..0000000000 --- a/tools/lib/lzo_stream.h +++ /dev/null @@ -1,36 +0,0 @@ -#/* $Id: lzo_stream.h,v 1.3 2003/09/30 15:22:53 mjw Exp $ */ -/* - * Copyright (C) 2003 Hewlett-Packard Company. - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _SP_LZO_STREAM_H_ -#define _SP_LZO_STREAM_H_ - -#ifndef __KERNEL__ -#include "iostream.h" - -extern IOStream *lzo_stream_new(IOStream *io, const char *mode); -extern IOStream *lzo_stream_fopen(const char *file, const char *mode); -extern IOStream *lzo_stream_fdopen(int fd, const char *mode); -extern IOStream *lzo_stream_io(IOStream *zio); - -extern int lzo_stream_plain_bytes(IOStream *io); -extern int lzo_stream_comp_bytes(IOStream *io); -extern float lzo_stream_ratio(IOStream *io); - -#endif -#endif /* !_SP_FILE_STREAM_H_ */ diff --git a/tools/lib/marshal.c b/tools/lib/marshal.c deleted file mode 100644 index 21691d4412..0000000000 --- a/tools/lib/marshal.c +++ /dev/null @@ -1,207 +0,0 @@ -#include -#include "sys_net.h" -#include "allocate.h" -#include "marshal.h" - -#define dprintf(fmt, args...) IOStream_print(iostdout, "[DEBUG] %s" fmt, __FUNCTION__, ##args) -#define wprintf(fmt, args...) IOStream_print(iostderr, "[WARN] %s" fmt, __FUNCTION__, ##args) -#define iprintf(fmt, args...) IOStream_print(iostdout, "[INFO] %s" fmt, __FUNCTION__, ##args) -#define eprintf(fmt, args...) IOStream_print(iostderr, "[ERROR] %s" fmt, __FUNCTION__, ##args) - - -#define ARRAY_SIZE(ary) (sizeof(ary)/sizeof((ary)[0])) - -/* Messages are coded as msgid followed by message fields. - * Initial message on any channel is hello - so can check version - * compatibility. - * - * char* -> uint16_t:n - * ints/uints go as suitable number of bytes (e.g. uint16_t is 2 bytes). - * optional fields go as '1' or '0' (the 0/1 is 1 byte). - * lists go as ('1' )* '0' - */ - -int marshal_flush(IOStream *io){ - int err = 0; - err = IOStream_flush(io); - return err; -} - -int marshal_bytes(IOStream *io, void *s, uint32_t s_n){ - int err = 0; - int n; - n = IOStream_write(io, s, s_n); - if(n < 0){ - err = n; - } else if (n < s_n){ - wprintf("> Wanted %d, got %d\n", s_n, n); - err = -EIO; - } - return err; -} - -int unmarshal_bytes(IOStream *io, void *s, uint32_t s_n){ - int err = 0; - int n; - //dprintf("> s_n=%d\n", s_n); - n = IOStream_read(io, s, s_n); - //dprintf("> n=%d\n", n); - if(n < 0){ - err = n; - } else if(n < s_n){ - wprintf("> Wanted %d, got %d\n", s_n, n); - err = -EIO; - } - //dprintf("< err=%d\n", err); - return err; -} - -int marshal_uint8(IOStream *io, uint8_t x){ - return marshal_bytes(io, &x, sizeof(x)); -} - -int unmarshal_uint8(IOStream *io, uint8_t *x){ - return unmarshal_bytes(io, x, sizeof(*x)); -} - -int marshal_uint16(IOStream *io, uint16_t x){ - x = htons(x); - return marshal_bytes(io, &x, sizeof(x)); -} - -int unmarshal_uint16(IOStream *io, uint16_t *x){ - int err = 0; - err = unmarshal_bytes(io, x, sizeof(*x)); - *x = ntohs(*x); - return err; -} - -int marshal_int32(IOStream *io, int32_t x){ - int err = 0; - //dprintf("> x=%d\n", x); - x = htonl(x); - err = marshal_bytes(io, &x, sizeof(x)); - //dprintf("< err=%d\n", err); - return err; -} - -int unmarshal_int32(IOStream *io, int32_t *x){ - int err = 0; - //dprintf(">\n"); - err = unmarshal_bytes(io, x, sizeof(*x)); - *x = ntohl(*x); - //dprintf("< err=%d x=%d\n", err, *x); - return err; -} - -int marshal_uint32(IOStream *io, uint32_t x){ - int err = 0; - //dprintf("> x=%u\n", x); - x = htonl(x); - err = marshal_bytes(io, &x, sizeof(x)); - //dprintf("< err=%d\n", err); - return err; -} - -int unmarshal_uint32(IOStream *io, uint32_t *x){ - int err = 0; - //dprintf(">\n"); - err = unmarshal_bytes(io, x, sizeof(*x)); - *x = ntohl(*x); - //dprintf("< err=%d x=%u\n", err, *x); - return err; -} - -int marshal_uint64(IOStream *io, uint64_t x){ - int err; - err = marshal_uint32(io, (uint32_t) ((x >> 32) & 0xffffffff)); - if(err) goto exit; - err = marshal_uint32(io, (uint32_t) ( x & 0xffffffff)); - exit: - return err; -} - -int unmarshal_uint64(IOStream *io, uint64_t *x){ - int err = 0; - uint32_t hi, lo; - err = unmarshal_uint32(io, &hi); - if(err) goto exit; - err = unmarshal_uint32(io, &lo); - *x = (((uint64_t) hi) << 32) | lo; - exit: - return err; -} - -int marshal_net16(IOStream *io, net16_t x){ - return marshal_bytes(io, &x, sizeof(x)); -} - -int unmarshal_net16(IOStream *io, net16_t *x){ - int err = 0; - err = unmarshal_bytes(io, x, sizeof(*x)); - return err; -} - -int marshal_net32(IOStream *io, net32_t x){ - return marshal_bytes(io, &x, sizeof(x)); -} - -int unmarshal_net32(IOStream *io, net32_t *x){ - int err = 0; - err = unmarshal_bytes(io, x, sizeof(*x)); - return err; -} - -int marshal_string(IOStream *io, char *s, uint32_t s_n){ - int err; - //dprintf("> s=%s\n", s); - err = marshal_uint32(io, s_n); - if(err) goto exit; - err = marshal_bytes(io, s, s_n); - exit: - //dprintf("< err=%d\n", err); - return err; -} - -int unmarshal_string(IOStream *io, char *s, uint32_t s_n){ - int err = 0, val_n = 0; - //dprintf(">\n"); - err = unmarshal_uint32(io, &val_n); - if(err) goto exit; - if(val_n >= s_n){ - err = -EINVAL; - goto exit; - } - err = unmarshal_bytes(io, s, val_n); - if(err) goto exit; - s[val_n] = '\0'; - exit: - //dprintf("< err=%d s=%s\n", err, s); - return err; -} - -int unmarshal_new_string(IOStream *io, char **s, uint32_t *s_n){ - int err = 0, val_n = 0; - char *val = NULL; - //dprintf(">\n"); - err = unmarshal_uint32(io, &val_n); - if(err) goto exit; - val = allocate(val_n + 1); - if(!val){ - err = -ENOMEM; - goto exit; - } - err = unmarshal_bytes(io, val, val_n); - if(err) goto exit; - val[val_n] = '\0'; - exit: - if(err){ - if(val) deallocate(val); - val = NULL; - val_n = 0; - } - *s = val; - if(s_n) *s_n = val_n; - //dprintf("< err=%d s=%s\n", err, *s); - return err; -} diff --git a/tools/lib/marshal.h b/tools/lib/marshal.h deleted file mode 100644 index 9a9d465b9b..0000000000 --- a/tools/lib/marshal.h +++ /dev/null @@ -1,43 +0,0 @@ -/* $Id: marshal.h,v 1.1 2003/10/17 15:48:43 mjw Exp $ */ -#ifndef _SP_MARSHAL_H_ -#define _SP_MARSHAL_H_ - -#include "iostream.h" - -/** A 16-bit uint in network order, e.g. a port number. */ -typedef uint16_t net16_t; - -/** A 32-bit uint in network order, e.g. an IP address. */ -typedef uint32_t net32_t; - -extern int marshal_flush(IOStream *io); - -extern int marshal_bytes(IOStream *io, void *s, uint32_t s_n); -extern int unmarshal_bytes(IOStream *io, void *s, uint32_t s_n); - -extern int marshal_uint8(IOStream *io, uint8_t x); -extern int unmarshal_uint8(IOStream *io, uint8_t *x); - -extern int marshal_uint16(IOStream *io, uint16_t x); -extern int unmarshal_uint16(IOStream *io, uint16_t *x); - -extern int marshal_uint32(IOStream *io, uint32_t x); -extern int unmarshal_uint32(IOStream *io, uint32_t *x); - -extern int marshal_int32(IOStream *io, int32_t x); -extern int unmarshal_int32(IOStream *io, int32_t *x); - -extern int marshal_uint64(IOStream *io, uint64_t x); -extern int unmarshal_uint64(IOStream *io, uint64_t *x); - -extern int marshal_net16(IOStream *io, net16_t x); -extern int unmarshal_net16(IOStream *io, net16_t *x); - -extern int marshal_net32(IOStream *io, net32_t x); -extern int unmarshal_net32(IOStream *io, net32_t *x); - -extern int marshal_string(IOStream *io, char *s, uint32_t s_n); -extern int unmarshal_string(IOStream *io, char *s, uint32_t s_n); -extern int unmarshal_new_string(IOStream *io, char **s, uint32_t *s_n); - -#endif /* ! _SP_MARSHAL_H_ */ diff --git a/tools/lib/socket_stream.c b/tools/lib/socket_stream.c deleted file mode 100644 index cfa6e3abf0..0000000000 --- a/tools/lib/socket_stream.c +++ /dev/null @@ -1,259 +0,0 @@ -/* $Id: socket_stream.c,v 1.9 2004/03/05 14:45:34 mjw Exp $ */ -/* - * Copyright (C) 2004 Mike Wray - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/** @file - * An IOStream implementation using sockets. - */ - -#include -#include -#include -#include -#include -#include "allocate.h" -#include "socket_stream.h" - -#define MODULE_NAME "sock" -#define DEBUG 0 -//#undef DEBUG -#include "debug.h" - -static int socket_read(IOStream *s, void *buf, size_t n); -static int socket_write(IOStream *s, const void *buf, size_t n); -static int socket_error(IOStream *s); -static int socket_close(IOStream *s); -static void socket_free(IOStream *s); -static int socket_flush(IOStream *s); - -/** Methods used by a socket IOStream. */ -static const IOMethods socket_methods = { - read: socket_read, - write: socket_write, - error: socket_error, - close: socket_close, - free: socket_free, - flush: socket_flush, -}; - -/** Get the socket data. - * - * @param io socket stream - * @return data - */ -static inline SocketData * socket_data(IOStream *io){ - return (SocketData *)io->data; -} - -/** Test if a stream is a socket stream. - * - * @param io stream - * @return 0 if a socket stream, -EINVAL if not - */ -int socket_stream_check(IOStream *io){ - return (io && io->methods == &socket_methods ? 0 : -EINVAL); -} - -/** Get the data for a socket stream. - * - * @param io stream - * @param data return value for the data - * @return 0 if a socket stream, -EINVAL if not - */ -int socket_stream_data(IOStream *io, SocketData **data){ - int err = socket_stream_check(io); - if(err){ - *data = NULL; - } else { - *data = socket_data(io); - } - return err; -} - -/** Set the destination address for a socket stream. - * - * @param io stream - * @param addr address - * @return 0 if a socket stream, -EINVAL if not - */ -int socket_stream_set_addr(IOStream *io, struct sockaddr_in *addr){ - int err = 0; - SocketData *data = NULL; - err = socket_stream_data(io, &data); - if(!err){ - data->daddr = *addr; - } - return err; -} - -/** Set the send flags for a socket stream. - * - * @param io stream - * @param flags flags - * @return 0 if a socket stream, -EINVAL if not - */ -int socket_stream_set_flags(IOStream *io, int flags){ - int err = 0; - SocketData *data = NULL; - err = socket_stream_data(io, &data); - if(!err){ - data->flags = flags; - } - return err; -} - -/** Write to the underlying socket using sendto. - * - * @param stream input - * @param buf where to put input - * @param n number of bytes to write - * @return number of bytes written - */ -static int socket_write(IOStream *s, const void *buf, size_t n){ - SocketData *data = socket_data(s); - struct sockaddr *daddr = (struct sockaddr *)&data->daddr; - socklen_t daddr_n = sizeof(data->daddr); - int k; - dprintf("> sock=%d addr=%s:%d n=%d\n", - data->fd, inet_ntoa(data->daddr.sin_addr), ntohs(data->daddr.sin_port), n); - if(0){ - struct sockaddr_in self = {}; - socklen_t self_n; - getsockname(data->fd, (struct sockaddr *)&self, &self_n); - dprintf("> sockname sock=%d %s:%d\n", - data->fd, inet_ntoa(self.sin_addr), ntohs(self.sin_port)); - } - k = sendto(data->fd, buf, n, data->flags, daddr, daddr_n); - dprintf("> sendto=%d\n", k); - return k; -} - -/** Read from the underlying stream using recv(); - * - * @param stream input - * @param buf where to put input - * @param n number of bytes to read - * @return number of bytes read - */ -static int socket_read(IOStream *s, void *buf, size_t n){ - SocketData *data = socket_data(s); - int k; - struct sockaddr *saddr = (struct sockaddr *)&data->saddr; - socklen_t saddr_n = sizeof(data->saddr); - k = recvfrom(data->fd, buf, n, data->flags, saddr, &saddr_n); - return k; -} - -/** Print to the underlying socket. - * - * @param s socket stream - * @param msg format to use - * @param args arguments - * @return result of the print - */ -static int socket_print(IOStream *s, const char *msg, va_list args){ - SocketData *data = socket_data(s); - int n; - n = vsnprintf(data->buf, data->buf_n - 1, msg, args); - if(0 < n && n < data->buf_n){ - socket_write(s, data->buf, n); - } - return n; -} - -/** Read a character from the underlying socket - * - * @param s socket stream - * @return character read, IOSTREAM_EOF on end of socket (or error) - */ -static int socket_getc(IOStream *s){ - char b; - int n, c; - n = socket_read(s, &b, 1); - c = (n <= 0 ? IOSTREAM_EOF : b); - return c; -} - -/** Flush the socket (no-op). - * - * @param s socket stream - * @return 0 on success, error code otherwise - */ -static int socket_flush(IOStream *s){ - return 0; -} - -/** Check if a socket stream has an error (no-op). - * - * @param s socket stream - * @return 1 if has an error, 0 otherwise - */ -static int socket_error(IOStream *s){ - // Read SOL_SOCKET/SO_ERROR ? - return 0; -} - -/** Close a socket stream. - * - * @param s socket stream to close - * @return result of the close - */ -static int socket_close(IOStream *s){ - SocketData *data = socket_data(s); - return close(data->fd); -} - -/** Free a socket stream. - * - * @param s socket stream - */ -static void socket_free(IOStream *s){ - SocketData *data = socket_data(s); - deallocate(data); -} - -/** Create an IOStream for a socket. - * - * @param fd socket to wtap - * @return new IOStream using fd for i/o - */ -IOStream *socket_stream_new(int fd){ - int err = -ENOMEM; - IOStream *io = NULL; - SocketData *data = NULL; - - io = ALLOCATE(IOStream); - if(!io) goto exit; - io->methods = &socket_methods; - data = ALLOCATE(SocketData); - if(!data) goto exit; - io->data = data; - data->fd = fd; - data->buf_n = sizeof(data->buf); - err = 0; - exit: - if(err){ - if(io){ - if(data) deallocate(data); - deallocate(io); - io = NULL; - } - } - return io; -} - diff --git a/tools/lib/socket_stream.h b/tools/lib/socket_stream.h deleted file mode 100644 index 5b8515f6b3..0000000000 --- a/tools/lib/socket_stream.h +++ /dev/null @@ -1,54 +0,0 @@ -/* $Id: socket_stream.h,v 1.2 2004/03/04 17:38:13 mjw Exp $ */ -/* - * Copyright (C) 2004 Mike Wray - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _XEN_LIB_SOCKET_STREAM_H_ -#define _XEN_LIB_SOCKET_STREAM_H_ - -#ifndef __KERNEL__ -#include "iostream.h" -#include - -#include -#include -#include - -/** Data associated with a socket stream. */ -typedef struct SocketData { - /** The socket file descriptor. */ - int fd; - /** Source address from last read (recvfrom). */ - struct sockaddr_in saddr; - /** Destination address for writes (sendto). */ - struct sockaddr_in daddr; - /** Write flags (sendto). */ - int flags; - /** Buffer size. */ - int buf_n; - /** Buffer for formatted printing. */ - char buf[1024]; -} SocketData; - -extern IOStream *socket_stream_new(int fd); -extern int socket_stream_data(IOStream *io, SocketData **data); -extern int socket_stream_check(IOStream *io); -extern int socket_stream_set_addr(IOStream *io, struct sockaddr_in *addr); -extern int socket_stream_set_flags(IOStream *io, int flags); - -#endif -#endif /* !_XEN_LIB_SOCKET_STREAM_H_ */ diff --git a/tools/lib/string_stream.c b/tools/lib/string_stream.c deleted file mode 100644 index c3cf423d84..0000000000 --- a/tools/lib/string_stream.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (C) 2001, 2002 Hewlett-Packard Company. - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/** @file - * IOStream subtype for input and output to strings. - * Usable from user or kernel code (with __KERNEL__ defined). - */ - -#include "sys_string.h" -#include "string_stream.h" -#include "allocate.h" - -static int string_print(IOStream *io, const char *msg, va_list args); -static int string_getc(IOStream *io); -static int string_error(IOStream *io); -static int string_close(IOStream *io); -static void string_free(IOStream *io); - -/** Methods for a string stream. */ -static IOMethods string_methods = { - //print: string_print, - //getc: string_getc, - error: string_error, - close: string_close, - free: string_free, -}; - -/** Get the string stream state. - * - * @param io string stream - * @return state - */ -static inline StringData *get_string_data(IOStream *io){ - return (StringData*)io->data; -} - -/** Read a character from a string stream. - * - * @param io string stream - * @return character read, IOSTREAM_EOF if no more input - */ -static int string_getc(IOStream *io){ - StringData *data = get_string_data(io); - int c = IOSTREAM_EOF; - char *s = data->in; - - if(s && s < data->end){ - c = (unsigned)*s; - data->in = s+1; - } - return c; -} - -/** Print to a string stream. - * Formats the data to an internal buffer and prints it. - * The formatted data must fit into the internal buffer. - * - * @param io string stream - * @param format print format - * @param args print arguments - * @return result of the print - */ -static int string_print(IOStream *io, const char *msg, va_list args){ - StringData *data = get_string_data(io); - int k = data->end - data->out; - int n = vsnprintf(data->out, k, (char*)msg, args); - if(n < 0 || n > k ){ - n = k; - IOStream_close(io); - } else { - data->out += n; - } - return n; -} - -/** Test if a string stream has an error. - * - * @param io string stream - * @return 0 if ok, error code otherwise - */ -static int string_error(IOStream *io){ - StringData *data = get_string_data(io); - return data->out == NULL; -} - -/** Close a string stream. - * - * @param io string stream - * @return 0 - */ -static int string_close(IOStream *io){ - StringData *data = get_string_data(io); - data->in = NULL; - data->out = NULL; - return 0; -} - -/** Free a string stream. - * The stream must have been allocated, not statically created. - * The stream state is freed, but the underlying string is not. - * - * @param io string stream - */ -static void string_free(IOStream *io){ - StringData *data = get_string_data(io); - zero(data, sizeof(*data)); - deallocate(data); -} - -/** Get the methods to use for a string stream. - * - * @return methods - */ -IOMethods *string_stream_get_methods(void){ - return &string_methods; -} - -/** Initialise a string stream, usually from static data. - * - * @param io address of IOStream to fill in - * @param data address of StringData to fill in - * @param s string to use - * @param n length of the string - */ -void string_stream_init(IOStream *io, StringData *data, char *s, int n){ - if(data && io){ - zero(data, sizeof(*data)); - data->string = (char*)s; - data->in = data->string; - data->out = data->string; - data->size = n; - data->end = data->string + n; - zero(io, sizeof(*io)); - io->methods = &string_methods; - io->data = data; - } -} - -/** Allocate and initialise a string stream. - * - * @param s string to use - * @param n length of the string - * @return new stream (free using IOStream_free) - */ -IOStream *string_stream_new(char *s, int n){ - int ok = 0; - StringData *data = ALLOCATE(StringData); - IOStream *io = ALLOCATE(IOStream); - if(data && io){ - ok = 1; - string_stream_init(io, data, s, n); - } - if(!ok){ - deallocate(data); - deallocate(io); - io = NULL; - } - return io; -} diff --git a/tools/lib/string_stream.h b/tools/lib/string_stream.h deleted file mode 100644 index 36d764b265..0000000000 --- a/tools/lib/string_stream.h +++ /dev/null @@ -1,46 +0,0 @@ -/* $Id: string_stream.h,v 1.1 2003/08/22 14:25:48 mjw Exp $ */ -/* - * Copyright (C) 2001, 2002 Hewlett-Packard Company. - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _SP_STRING_STREAM_H_ -#define _SP_STRING_STREAM_H_ - -#include "iostream.h" - -/** Internal state for a string stream. - * Exposed here so that string streams can be statically created, using - * string_stream_init(). - */ -typedef struct { - /** The string used for input and ouput. */ - char *string; - /** Output pointer. */ - char *out; - /** Input pointer. */ - char *in; - /** Length of string. */ - int size; - /** End marker. */ - char *end; -} StringData; - -extern IOMethods *string_stream_get_methods(void); -extern IOStream *string_stream_new(char *s, int n); -extern void string_stream_init(IOStream *stream, StringData *data, char *s, int n); - -#endif /* !_SP_STRING_STREAM_H_ */ diff --git a/tools/lib/sxpr.c b/tools/lib/sxpr.c deleted file mode 100644 index adeffbe5eb..0000000000 --- a/tools/lib/sxpr.c +++ /dev/null @@ -1,935 +0,0 @@ -/* - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of the - * License, or (at your option) any later version. This library is - * distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include "sys_string.h" -#include "lexis.h" -#include "sys_net.h" -#include "hash_table.h" -#include "sxpr.h" - -#include -#undef free - -/** @file - * General representation of sxprs. - * Includes print, equal, and free functions for the sxpr types. - * - * Zero memory containing an Sxpr will have the value ONONE - this is intentional. - * When a function returning an sxpr cannot allocate memory we return ONOMEM. - * - */ - -static int atom_print(IOStream *io, Sxpr obj, unsigned flags); -static int atom_equal(Sxpr x, Sxpr y); -static void atom_free(Sxpr obj); - -static int string_print(IOStream *io, Sxpr obj, unsigned flags); -static int string_equal(Sxpr x, Sxpr y); -static void string_free(Sxpr obj); - -static int cons_print(IOStream *io, Sxpr obj, unsigned flags); -static int cons_equal(Sxpr x, Sxpr y); -static void cons_free(Sxpr obj); - -static int null_print(IOStream *io, Sxpr obj, unsigned flags); -static int none_print(IOStream *io, Sxpr obj, unsigned flags); -static int int_print(IOStream *io, Sxpr obj, unsigned flags); -static int bool_print(IOStream *io, Sxpr obj, unsigned flags); - -/** Type definitions. */ -static SxprType types[1024] = { - [T_NONE] { type: T_NONE, name: "none", print: none_print }, - [T_NULL] { type: T_NULL, name: "null", print: null_print }, - [T_UINT] { type: T_UINT, name: "int", print: int_print, }, - [T_BOOL] { type: T_BOOL, name: "bool", print: bool_print, }, - [T_ATOM] { type: T_ATOM, name: "atom", print: atom_print, - pointer: TRUE, - free: atom_free, - equal: atom_equal, - }, - [T_STRING] { type: T_STRING, name: "string", print: string_print, - pointer: TRUE, - free: string_free, - equal: string_equal, - }, - [T_CONS] { type: T_CONS, name: "cons", print: cons_print, - pointer: TRUE, - free: cons_free, - equal: cons_equal, - }, -}; - -/** Number of entries in the types array. */ -static int type_sup = sizeof(types)/sizeof(types[0]); - -/** Get the type definition for a given type code. - * - * @param ty type code - * @return type definition or null - */ -SxprType *get_sxpr_type(int ty){ - if(0 <= ty && ty < type_sup){ - return types+ty; - } - return NULL; -} - -/** The default print function. - * - * @param io stream to print to - * @param x sxpr to print - * @param flags print flags - * @return number of bytes written on success - */ -int default_print(IOStream *io, Sxpr x, unsigned flags){ - return IOStream_print(io, "#<%u %lu>\n", get_type(x), get_ul(x)); -} - -/** The default equal function. - * Uses eq(). - * - * @param x sxpr to compare - * @param y sxpr to compare - * @return 1 if equal, 0 otherwise - */ -int default_equal(Sxpr x, Sxpr y){ - return eq(x, y); -} - -/** General sxpr print function. - * Prints an sxpr on a stream using the print function for the sxpr type. - * Printing is controlled by flags from the PrintFlags enum. - * If PRINT_TYPE is in the flags the sxpr type is printed before the sxpr - * (for debugging). - * - * @param io stream to print to - * @param x sxpr to print - * @param flags print flags - * @return number of bytes written - */ -int objprint(IOStream *io, Sxpr x, unsigned flags){ - SxprType *def = get_sxpr_type(get_type(x)); - ObjPrintFn *print_fn = (def && def->print ? def->print : default_print); - int k = 0; - if(!io) return k; - if(flags & PRINT_TYPE){ - k += IOStream_print(io, "%s:", def->name); - } - k += print_fn(io, x, flags); - return k; -} - -/** General sxpr free function. - * Frees an sxpr using the free function for its type. - * Free functions must recursively free any subsxprs. - * If no function is defined then the default is to - * free sxprs whose type has pointer true. - * Sxprs must not be used after freeing. - * - * @param x sxpr to free - */ -void objfree(Sxpr x){ - SxprType *def = get_sxpr_type(get_type(x)); - - if(def){ - if(def->free){ - def->free(x); - } else if (def->pointer){ - hfree(x); - } - } -} - -/** General sxpr equality function. - * Compares x and y using the equal function for x. - * Uses default_equal() if x has no equal function. - * - * @param x sxpr to compare - * @param y sxpr to compare - * @return 1 if equal, 0 otherwise - */ -int objequal(Sxpr x, Sxpr y){ - SxprType *def = get_sxpr_type(get_type(x)); - ObjEqualFn *equal_fn = (def && def->equal ? def->equal : default_equal); - return equal_fn(x, y); -} - -/** Search for a key in an alist. - * An alist is a list of conses, where the cars - * of the conses are the keys. Compares keys using equality. - * - * @param k key - * @param l alist to search - * @return first element of l with car k, or ONULL - */ -Sxpr assoc(Sxpr k, Sxpr l){ - for( ; CONSP(l) ; l = CDR(l)){ - Sxpr x = CAR(l); - if(CONSP(x) && objequal(k, CAR(x))){ - return x; - } - } - return ONULL; -} - -/** Search for a key in an alist. - * An alist is a list of conses, where the cars - * of the conses are the keys. Compares keys using eq. - * - * @param k key - * @param l alist to search - * @return first element of l with car k, or ONULL - */ -Sxpr assocq(Sxpr k, Sxpr l){ - for( ; CONSP(l); l = CDR(l)){ - Sxpr x = CAR(l); - if(CONSP(x) && eq(k, CAR(x))){ - return x; - } - } - return ONULL; -} - -/** Add a new key and value to an alist. - * - * @param k key - * @param l value - * @param l alist - * @return l with the new cell added to the front - */ -Sxpr acons(Sxpr k, Sxpr v, Sxpr l){ - Sxpr x, y; - x = cons_new(k, v); - if(NOMEMP(x)) return x; - y = cons_new(x, l); - if(NOMEMP(y)) cons_free_cells(x); - return y; -} - -/** Test if a list contains an element. - * Uses sxpr equality. - * - * @param l list - * @param x element to look for - * @return a tail of l with x as car, or ONULL - */ -Sxpr cons_member(Sxpr l, Sxpr x){ - for( ; CONSP(l) && !eq(x, CAR(l)); l = CDR(l)){} - return l; -} - -/** Test if a list contains an element satisfying a test. - * The test function is called with v and an element of the list. - * - * @param l list - * @param test_fn test function to use - * @param v value for first argument to the test - * @return a tail of l with car satisfying the test, or 0 - */ -Sxpr cons_member_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v){ - for( ; CONSP(l) && !test_fn(v, CAR(l)); l = CDR(l)){ } - return l; -} - -/** Test if the elements of list 't' are a subset of the elements - * of list 's'. Element order is not significant. - * - * @param s element list to check subset of - * @param t element list to check if is a subset - * @return 1 if is a subset, 0 otherwise - */ -int cons_subset(Sxpr s, Sxpr t){ - for( ; CONSP(t); t = CDR(t)){ - if(!CONSP(cons_member(s, CAR(t)))){ - return 0; - } - } - return 1; -} - -/** Test if two lists have equal sets of elements. - * Element order is not significant. - * - * @param s list to check - * @param t list to check - * @return 1 if equal, 0 otherwise - */ -int cons_set_equal(Sxpr s, Sxpr t){ - return cons_subset(s, t) && cons_subset(t, s); -} - -#ifdef USE_GC -/*============================================================================*/ -/* The functions inside this ifdef are only safe if GC is used. - * Otherwise they may leak memory. - */ - -/** Remove an element from a list (GC only). - * Uses sxpr equality and removes all instances, even - * if there are more than one. - * - * @param l list to remove elements from - * @param x element to remove - * @return modified input list - */ -Sxpr cons_remove(Sxpr l, Sxpr x){ - return cons_remove_if(l, eq, x); -} - -/** Remove elements satisfying a test (GC only). - * The test function is called with v and an element of the set. - * - * @param l list to remove elements from - * @param test_fn function to use to decide if an element should be removed - * @return modified input list - */ -Sxpr cons_remove_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v){ - Sxpr prev = ONULL, elt, next; - - for(elt = l; CONSP(elt); elt = next){ - next = CDR(elt); - if(test_fn(v, CAR(elt))){ - if(NULLP(prev)){ - l = next; - } else { - CDR(prev) = next; - } - } - } - return l; -} - -/** Set the value for a key in an alist (GC only). - * If the key is present, changes the value, otherwise - * adds a new cell. - * - * @param k key - * @param v value - * @param l alist - * @return modified or extended list - */ -Sxpr setf(Sxpr k, Sxpr v, Sxpr l){ - Sxpr e = assoc(k, l); - if(NULLP(e)){ - l = acons(k, v, l); - } else { - CAR(CDR(e)) = v; - } - return l; -} -/*============================================================================*/ -#endif /* USE_GC */ - -/** Create a new atom with the given name. - * - * @param name the name - * @return new atom - */ -Sxpr atom_new(char *name){ - Sxpr n, obj = ONOMEM; - - n = string_new(name); - if(NOMEMP(n)) goto exit; - obj = HALLOC(ObjAtom, T_ATOM); - if(NOMEMP(obj)) goto exit; - OBJ_ATOM(obj)->name = n; - exit: - return obj; -} - -/** Free an atom. - * - * @param obj to free - */ -void atom_free(Sxpr obj){ - // Interned atoms are shared, so do not free. - if(OBJ_ATOM(obj)->interned) return; - objfree(OBJ_ATOM(obj)->name); - hfree(obj); -} - -/** Print an atom. Prints the atom name. - * - * @param io stream to print to - * @param obj to print - * @param flags print flags - * @return number of bytes printed - */ -int atom_print(IOStream *io, Sxpr obj, unsigned flags){ - //return string_print(io, OBJ_ATOM(obj)->name, (flags | PRINT_RAW)); - return string_print(io, OBJ_ATOM(obj)->name, flags); -} - -/** Atom equality. - * - * @param x to compare - * @param y to compare - * @return 1 if equal, 0 otherwise - */ -int atom_equal(Sxpr x, Sxpr y){ - int ok; - ok = eq(x, y); - if(ok) goto exit; - ok = ATOMP(y) && string_equal(OBJ_ATOM(x)->name, OBJ_ATOM(y)->name); - if(ok) goto exit; - ok = STRINGP(y) && string_equal(OBJ_ATOM(x)->name, y); - exit: - return ok; -} - -/** Get the name of an atom. - * - * @param obj atom - * @return name - */ -char * atom_name(Sxpr obj){ - return string_string(OBJ_ATOM(obj)->name); -} - -/** Get the C string from a string sxpr. - * - * @param obj string sxpr - * @return string - */ -char * string_string(Sxpr obj){ - return OBJ_STRING(obj); -} - -/** Get the length of a string. - * - * @param obj string - * @return length - */ -int string_length(Sxpr obj){ - return strlen(OBJ_STRING(obj)); -} - -/** Create a new string. The input string is copied, - * and must be null-terminated. - * - * @param s characters to put in the string - * @return new sxpr - */ -Sxpr string_new(char *s){ - int n = (s ? strlen(s) : 0); - Sxpr obj; - obj = halloc(n+1, T_STRING); - if(!NOMEMP(obj)){ - char *str = OBJ_STRING(obj); - strncpy(str, s, n); - str[n] = '\0'; - } - return obj; -} - -/** Free a string. - * - * @param obj to free - */ -void string_free(Sxpr obj){ - hfree(obj); -} - -/** Determine if a string needs escapes when printed - * using the given flags. - * - * @param str string to check - * @param flags print flags - * @return 1 if needs escapes, 0 otherwise - */ -int needs_escapes(char *str, unsigned flags){ - char *c; - int val = 0; - - if(str){ - for(c=str; *c; c++){ - if(in_alpha_class(*c)) continue; - if(in_decimal_digit_class(*c)) continue; - if(in_class(*c, "/._+:@~-")) continue; - val = 1; - break; - } - } - //printf("\n> val=%d str=|%s|\n", val, str); - return val; -} - -/** Print a string to a stream, with escapes if necessary. - * - * @param io stream to print to - * @param str string - * @param flags print flags - * @return number of bytes written - */ -int _string_print(IOStream *io, char *str, unsigned flags){ - int k = 0; - if((flags & PRINT_RAW) || !needs_escapes(str, flags)){ - k += IOStream_print(io, str); - } else { - k += IOStream_print(io, "\""); - if(str){ - char *s; - for(s = str; *s; s++){ - if(*s < ' ' || *s >= 127 ){ - switch(*s){ - case '\a': k += IOStream_print(io, "\\a"); break; - case '\b': k += IOStream_print(io, "\\b"); break; - case '\f': k += IOStream_print(io, "\\f"); break; - case '\n': k += IOStream_print(io, "\\n"); break; - case '\r': k += IOStream_print(io, "\\r"); break; - case '\t': k += IOStream_print(io, "\\t"); break; - case '\v': k += IOStream_print(io, "\\v"); break; - default: - // Octal escape; - k += IOStream_print(io, "\\%o", *s); - break; - } - } else if(*s == c_double_quote || - *s == c_single_quote || - *s == c_escape){ - k += IOStream_print(io, "\\%c", *s); - } else { - k+= IOStream_print(io, "%c", *s); - } - } - } - k += IOStream_print(io, "\""); - } - return k; -} - -/** Print a string to a stream, with escapes if necessary. - * - * @param io stream to print to - * @param obj string - * @param flags print flags - * @return number of bytes written - */ -int string_print(IOStream *io, Sxpr obj, unsigned flags){ - return _string_print(io, OBJ_STRING(obj), flags); -} - -/** Compare an sxpr with a string for equality. - * - * @param x string to compare with - * @param y sxpr to compare - * @return 1 if equal, 0 otherwise - */ -int string_equal(Sxpr x, Sxpr y){ - int ok = 0; - ok = eq(x,y); - if(ok) goto exit; - ok = has_type(y, T_STRING) && !strcmp(OBJ_STRING(x), OBJ_STRING(y)); - if(ok) goto exit; - ok = has_type(y, T_ATOM) && !strcmp(OBJ_STRING(x), atom_name(y)); - exit: - return ok; -} - -/** Create a new cons cell. - * The cell is ONOMEM if either argument is. - * - * @param car sxpr for the car - * @param cdr sxpr for the cdr - * @return new cons - */ -Sxpr cons_new(Sxpr car, Sxpr cdr){ - Sxpr obj; - if(NOMEMP(car) || NOMEMP(cdr)){ - obj = ONOMEM; - } else { - obj = HALLOC(ObjCons, T_CONS); - if(!NOMEMP(obj)){ - ObjCons *z = OBJ_CONS(obj); - z->car = car; - z->cdr = cdr; - } - } - return obj; -} - -/** Push a new element onto a list. - * - * @param list list to add to - * @param elt element to add - * @return 0 if successful, error code otherwise - */ -int cons_push(Sxpr *list, Sxpr elt){ - Sxpr l; - l = cons_new(elt, *list); - if(NOMEMP(l)) return -ENOMEM; - *list = l; - return 0; -} - -/** Free a cons. Recursively frees the car and cdr. - * - * @param obj to free - */ -void cons_free(Sxpr obj){ - Sxpr next; - for(; CONSP(obj); obj = next){ - next = CDR(obj); - objfree(CAR(obj)); - hfree(obj); - } - if(!NULLP(obj)){ - objfree(obj); - } -} - -/** Free a cons and its cdr cells, but not the car sxprs. - * Does nothing if called on something that is not a cons. - * - * @param obj to free - */ -void cons_free_cells(Sxpr obj){ - Sxpr next; - for(; CONSP(obj); obj = next){ - next = CDR(obj); - hfree(obj); - } -} - -/** Print a cons. - * Prints the cons in list format if the cdrs are conses. - * uses pair (dot) format if the last cdr is not a cons (or null). - * - * @param io stream to print to - * @param obj to print - * @param flags print flags - * @return number of bytes written - */ -int cons_print(IOStream *io, Sxpr obj, unsigned flags){ - int first = 1; - int k = 0; - k += IOStream_print(io, "("); - for( ; CONSP(obj) ; obj = CDR(obj)){ - if(first){ - first = 0; - } else { - k += IOStream_print(io, " "); - } - k += objprint(io, CAR(obj), flags); - } - if(!NULLP(obj)){ - k += IOStream_print(io, " . "); - k += objprint(io, obj, flags); - } - k += IOStream_print(io, ")"); - return (IOStream_error(io) ? -1 : k); -} - -/** Compare a cons with another sxpr for equality. - * If y is a cons, compares the cars and cdrs recursively. - * - * @param x cons to compare - * @param y sxpr to compare - * @return 1 if equal, 0 otherwise - */ -int cons_equal(Sxpr x, Sxpr y){ - return CONSP(y) && - objequal(CAR(x), CAR(y)) && - objequal(CDR(x), CDR(y)); -} - -/** Return the length of a cons list. - * - * @param obj list - * @return length - */ -int cons_length(Sxpr obj){ - int count = 0; - for( ; CONSP(obj); obj = CDR(obj)){ - count++; - } - return count; -} - -/** Destructively reverse a cons list in-place. - * If the argument is not a cons it is returned unchanged. - * - * @param l to reverse - * @return reversed list - */ -Sxpr nrev(Sxpr l){ - if(CONSP(l)){ - // Iterate down the cells in the list making the cdr of - // each cell point to the previous cell. The last cell - // is the head of the reversed list. - Sxpr prev = ONULL; - Sxpr cell = l; - Sxpr next; - - while(1){ - next = CDR(cell); - CDR(cell) = prev; - if(!CONSP(next)) break; - prev = cell; - cell = next; - } - l = cell; - } - return l; -} - -/** Print the null sxpr. - * - * @param io stream to print to - * @param obj to print - * @param flags print flags - * @return number of bytes written - */ -static int null_print(IOStream *io, Sxpr obj, unsigned flags){ - return IOStream_print(io, "()"); -} - -/** Print the `unspecified' sxpr none. - * - * @param io stream to print to - * @param obj to print - * @param flags print flags - * @return number of bytes written - */ -static int none_print(IOStream *io, Sxpr obj, unsigned flags){ - return IOStream_print(io, ""); -} - -/** Print an integer. - * - * @param io stream to print to - * @param obj to print - * @param flags print flags - * @return number of bytes written - */ -static int int_print(IOStream *io, Sxpr obj, unsigned flags){ - return IOStream_print(io, "%d", OBJ_INT(obj)); -} - -/** Print a boolean. - * - * @param io stream to print to - * @param obj to print - * @param flags print flags - * @return number of bytes written - */ -static int bool_print(IOStream *io, Sxpr obj, unsigned flags){ - return IOStream_print(io, (OBJ_UINT(obj) ? k_true : k_false)); -} - -int sxprp(Sxpr obj, Sxpr name){ - return CONSP(obj) && objequal(CAR(obj), name); -} - -/** Get the name of an element. - * - * @param obj element - * @return name - */ -Sxpr sxpr_name(Sxpr obj){ - Sxpr val = ONONE; - if(CONSP(obj)){ - val = CAR(obj); - } else if(STRINGP(obj) || ATOMP(obj)){ - val = obj; - } - return val; -} - -int sxpr_is(Sxpr obj, char *s){ - if(ATOMP(obj)) return !strcmp(atom_name(obj), s); - if(STRINGP(obj)) return !strcmp(string_string(obj), s); - return 0; -} - -int sxpr_elementp(Sxpr obj, Sxpr name){ - return CONSP(obj) && objequal(CAR(obj), name); -} - -/** Get the attributes of an sxpr. - * - * @param obj sxpr - * @return attributes - */ -Sxpr sxpr_attributes(Sxpr obj){ - Sxpr val = ONULL; - if(CONSP(obj)){ - obj = CDR(obj); - if(CONSP(obj)){ - obj = CAR(obj); - if(sxprp(obj, intern("@"))){ - val = CDR(obj); - } - } - } - return val; -} - -Sxpr sxpr_attribute(Sxpr obj, Sxpr key, Sxpr def){ - Sxpr val = ONONE; - val = assoc(sxpr_attributes(obj), key); - if(CONSP(val) && CONSP(CDR(val))){ - val = CADR(def); - } else { - val = def; - } - return val; -} - -/** Get the children of an sxpr. - * - * @param obj sxpr - * @return children - */ -Sxpr sxpr_children(Sxpr obj){ - Sxpr val = ONULL; - if(CONSP(obj)){ - val = CDR(obj); - if(CONSP(val) && sxprp(CAR(val), intern("@"))){ - val = CDR(val); - } - } - return val; -} - -Sxpr sxpr_child(Sxpr obj, Sxpr name, Sxpr def){ - Sxpr val = ONONE; - Sxpr l; - for(l = sxpr_children(obj); CONSP(l); l = CDR(l)){ - if(sxprp(CAR(l), name)){ - val = CAR(l); - break; - } - } - if(NONEP(val)) val = def; - return val; -} - -Sxpr sxpr_child0(Sxpr obj, Sxpr def){ - Sxpr val = ONONE; - Sxpr l = sxpr_children(obj); - if(CONSP(l)){ - val = CAR(l); - } else { - val = def; - } - return val; -} - -Sxpr sxpr_child_value(Sxpr obj, Sxpr name, Sxpr def){ - Sxpr val = ONONE; - val = sxpr_child(obj, name, ONONE); - if(NONEP(val)){ - val = def; - } else { - val = sxpr_child0(val, def); - } - return val; -} - -/** Table of interned symbols. Indexed by symbol name. */ -static HashTable *symbols = NULL; - -/** Hash function for entries in the symbol table. - * - * @param key to hash - * @return hashcode - */ -static Hashcode sym_hash_fn(void *key){ - return hash_string((char*)key); -} - -/** Key equality function for the symbol table. - * - * @param x to compare - * @param y to compare - * @return 1 if equal, 0 otherwise - */ -static int sym_equal_fn(void *x, void *y){ - return !strcmp((char*)x, (char*)y); -} - -/** Entry free function for the symbol table. - * - * @param table the entry is in - * @param entry being freed - */ -static void sym_free_fn(HashTable *table, HTEntry *entry){ - if(entry){ - objfree(((ObjAtom*)entry->value)->name); - HTEntry_free(entry); - } -} - -/** Initialize the symbol table. - * - * @return 0 on sucess, error code otherwise - */ -static int init_symbols(void){ - symbols = HashTable_new(100); - if(symbols){ - symbols->key_hash_fn = sym_hash_fn; - symbols->key_equal_fn = sym_equal_fn; - symbols->entry_free_fn = sym_free_fn; - return 0; - } - return -1; -} - -/** Cleanup the symbol table. Frees the table and all its symbols. - */ -void cleanup_symbols(void){ - HashTable_free(symbols); - symbols = NULL; -} - -/** Get the interned symbol with the given name. - * No new symbol is created. - * - * @return symbol or null - */ -Sxpr get_symbol(char *sym){ - HTEntry *entry; - if(!symbols){ - if(init_symbols()) return ONOMEM; - return ONULL; - } - entry = HashTable_get_entry(symbols, sym); - if(entry){ - return OBJP(T_ATOM, entry->value); - } else { - return ONULL; - } -} - -/** Get the interned symbol with the given name. - * Creates a new symbol if necessary. - * - * @return symbol - */ -Sxpr intern(char *sym){ - Sxpr symbol = get_symbol(sym); - if(NULLP(symbol)){ - if(!symbols) return ONOMEM; - symbol = atom_new(sym); - if(!NOMEMP(symbol)){ - OBJ_ATOM(symbol)->interned = TRUE; - HashTable_add(symbols, atom_name(symbol), get_ptr(symbol)); - } - } - return symbol; -} diff --git a/tools/lib/sxpr.h b/tools/lib/sxpr.h deleted file mode 100644 index b90083139c..0000000000 --- a/tools/lib/sxpr.h +++ /dev/null @@ -1,413 +0,0 @@ -/* - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of the - * License, or (at your option) any later version. This library is - * distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _XEN_LIB_SXPR_H_ -#define _XEN_LIB_SXPR_H_ - -#include - -#include "hash_table.h" -#include "iostream.h" -#include "allocate.h" - -/** @file - * Definitions for rules and sxprs. - */ - -#ifndef NULL -#define NULL 0 -#endif - -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - -/** Sxpr type. */ -typedef int16_t TypeCode; - -/** A typed sxpr handle.*/ -typedef struct Sxpr { - /** Sxpr type. */ - TypeCode type; - union { - /** Sxpr value. */ - unsigned long ul; - /** Pointer. */ - void *ptr; - } v; -} Sxpr; - -/** Sxpr type to indicate out of memory. */ -#define T_NOMEM ((TypeCode)-1) -/** The 'unspecified' sxpr. */ -#define T_NONE ((TypeCode)0) -/** The empty list. */ -#define T_NULL ((TypeCode)1) -/** Unsigned integer. */ -#define T_UINT ((TypeCode)2) -/** A string. */ -#define T_STRING ((TypeCode)3) -/** An atom. */ -#define T_ATOM ((TypeCode)4) -/** A boolean. */ -#define T_BOOL ((TypeCode)5) - -/** A cons (pair or list). */ -#define T_CONS ((TypeCode)10) - -/** An error. */ -#define T_ERR ((TypeCode)40) - -/** An atom. */ -typedef struct ObjAtom { - Sxpr name; - Hashcode hashcode; - int interned; -} ObjAtom; - -/** A cons (pair). */ -typedef struct ObjCons { - Sxpr car; - Sxpr cdr; -} ObjCons; - -/** A vector. */ -typedef struct ObjVector { - int n; - Sxpr data[0]; -} ObjVector; - -/** Flags for sxpr printing. */ -enum PrintFlags { - PRINT_RAW = 0x001, - PRINT_TYPE = 0x002, - PRINT_PRETTY = 0x004, - PRINT_NUM = 0x008, -}; - -/** An integer sxpr. - * - * @param ty type - * @param val integer value - */ -#define OBJI(ty, val) (Sxpr){ type: (ty), v: { ul: (val) }} - -/** A pointer sxpr. - * If the pointer is non-null, returns an sxpr containing it. - * If the pointer is null, returns ONOMEM. - * - * @param ty type - * @param val pointer - */ -#define OBJP(ty, val) ((val) ? (Sxpr){ type: (ty), v: { ptr: (val) }} : ONOMEM) - -/** Make an integer sxpr containing a pointer. - * - * @param val pointer - */ -#define PTR(val) OBJP(T_UINT, (void*)(val)) - -/** Make an integer sxpr. - * @param x value - */ -#define OINT(x) OBJI(T_UINT, x) - -/** Make an error sxpr. - * - * @param x value - */ -#define OERR(x) OBJI(T_ERR, x) - -/** Out of memory constant. */ -#define ONOMEM OBJI(T_NOMEM, 0) - -/** The `unspecified' constant. */ -#define ONONE OBJI(T_NONE, 0) - -/** Empty list constant. */ -#define ONULL OBJI(T_NULL, 0) - -/** False constant. */ -#define OFALSE OBJI(T_BOOL, 0) - -/** True constant. */ -#define OTRUE OBJI(T_BOOL, 1) - -/* Recognizers for the various sxpr types. */ -#define ATOMP(obj) has_type(obj, T_ATOM) -#define BOOLP(obj) has_type(obj, T_BOOL) -#define CONSP(obj) has_type(obj, T_CONS) -#define ERRP(obj) has_type(obj, T_ERR) -#define INTP(obj) has_type(obj, T_UINT) -#define NOMEMP(obj) has_type(obj, T_NOMEM) -#define NONEP(obj) has_type(obj, T_NONE) -#define NULLP(obj) has_type(obj, T_NULL) -#define STRINGP(obj) has_type(obj, T_STRING) - -#define TRUEP(obj) get_ul(obj) - -/** Convert an sxpr to an unsigned integer. */ -#define OBJ_UINT(x) get_ul(x) -/** Convert an sxpr to an integer. */ -#define OBJ_INT(x) (int)get_ul(x) - -/* Conversions of sxprs to their values. - * No checking is done. - */ -#define OBJ_STRING(x) ((char*)get_ptr(x)) -#define OBJ_CONS(x) ((ObjCons*)get_ptr(x)) -#define OBJ_ATOM(x) ((ObjAtom*)get_ptr(x)) -#define OBJ_SET(x) ((ObjSet*)get_ptr(x)) -#define CAR(x) (OBJ_CONS(x)->car) -#define CDR(x) (OBJ_CONS(x)->cdr) - -#define CAAR(x) (CAR(CAR(x))) -#define CADR(x) (CAR(CDR(x))) -#define CDAR(x) (CDR(CAR(x))) -#define CDDR(x) (CDR(CDR(x))) - -/** Get the integer value from an sxpr. - * - * @param obj sxpr - * @return value - */ -static inline unsigned long get_ul(Sxpr obj){ - return obj.v.ul; -} - -/** Get the pointer value from an sxpr. - * - * @param obj sxpr - * @return value - */ -static inline void * get_ptr(Sxpr obj){ - return obj.v.ptr; -} - -/** Create an sxpr containing a pointer. - * - * @param type typecode - * @param val pointer - * @return sxpr - */ -static inline Sxpr obj_ptr(TypeCode type, void *val){ - return (Sxpr){ type: type, v: { ptr: val } }; -} - -/** Create an sxpr containing an integer. - * - * @param type typecode - * @param val integer - * @return sxpr - */ -static inline Sxpr obj_ul(TypeCode type, unsigned long val){ - return (Sxpr){ type: type, v: { ul: val } }; -} - -/** Get the type of an sxpr. - * - * @param obj sxpr - * @return type - */ -static inline TypeCode get_type(Sxpr obj){ - return obj.type; -} - -/** Check the type of an sxpr. - * - * @param obj sxpr - * @param type to check - * @return 1 if has the type, 0 otherwise - */ -static inline int has_type(Sxpr obj, TypeCode type){ - return get_type(obj) == type; -} - -/** Compare sxprs for literal equality of type and value. - * - * @param x sxpr to compare - * @param y sxpr to compare - * @return 1 if equal, 0 otherwise - */ -static inline int eq(Sxpr x, Sxpr y){ - return ((get_type(x) == get_type(y)) && (get_ul(x) == get_ul(y))); -} - -/** Checked version of CAR - * - * @param x sxpr - * @return CAR if a cons, x otherwise - */ -static inline Sxpr car(Sxpr x){ - return (CONSP(x) ? CAR(x) : x); -} - -/** Checked version of CDR. - * - * @param x sxpr - * @return CDR if a cons, null otherwise - */ -static inline Sxpr cdr(Sxpr x){ - return (CONSP(x) ? CDR(x) : ONULL); -} - -/** Allocate some memory and return an sxpr containing it. - * Returns ONOMEM if allocation failed. - * - * @param n number of bytes to allocate - * @param ty typecode - * @return sxpr - */ -static inline Sxpr halloc(size_t n, TypeCode ty){ - return OBJP(ty, allocate(n)); -} - -/** Allocate an sxpr containing a pointer to the given type. - * - * @param ty type (uses sizeof to determine how many bytes to allocate) - * @param code typecode - * @return sxpr, ONOMEM if allocation failed - */ -#define HALLOC(ty, code) halloc(sizeof(ty), code) - -typedef int ObjPrintFn(IOStream *io, Sxpr obj, unsigned flags); -typedef int ObjEqualFn(Sxpr obj, Sxpr other); -typedef void ObjFreeFn(Sxpr obj); - -/** An sxpr type definition. */ -typedef struct SxprType { - TypeCode type; - char *name; - int pointer; - ObjPrintFn *print; - ObjEqualFn *equal; - ObjFreeFn *free; -} SxprType; - - -extern SxprType *get_sxpr_type(int ty); - -/** Free the pointer in an sxpr. - * - * @param x sxpr containing a pointer - */ -static inline void hfree(Sxpr x){ - deallocate(get_ptr(x)); -} - -extern int objprint(IOStream *io, Sxpr x, unsigned flags); -extern int objequal(Sxpr x, Sxpr y); -extern void objfree(Sxpr x); - -extern void cons_free_cells(Sxpr obj); -extern Sxpr intern(char *s); - -extern Sxpr assoc(Sxpr k, Sxpr l); -extern Sxpr assocq(Sxpr k, Sxpr l); -extern Sxpr acons(Sxpr k, Sxpr v, Sxpr l); -extern Sxpr nrev(Sxpr l); -extern Sxpr cons_member(Sxpr l, Sxpr x); -extern Sxpr cons_member_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v); -extern int cons_subset(Sxpr s, Sxpr t); -extern int cons_set_equal(Sxpr s, Sxpr t); - -#ifdef USE_GC -extern Sxpr cons_remove(Sxpr l, Sxpr x); -extern Sxpr cons_remove_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v); -#endif - -extern Sxpr atom_new(char *name); -extern char * atom_name(Sxpr obj); - -extern Sxpr string_new(char *s); -extern char * string_string(Sxpr obj); -extern int string_length(Sxpr obj); - -extern Sxpr cons_new(Sxpr car, Sxpr cdr); -extern int cons_push(Sxpr *list, Sxpr elt); -extern int cons_length(Sxpr obj); - -Sxpr sxpr_name(Sxpr obj); -int sxpr_is(Sxpr obj, char *s); -int sxpr_elementp(Sxpr obj, Sxpr name); -Sxpr sxpr_attributes(Sxpr obj); -Sxpr sxpr_attribute(Sxpr obj, Sxpr key, Sxpr def); -Sxpr sxpr_children(Sxpr obj); -Sxpr sxpr_child(Sxpr obj, Sxpr name, Sxpr def); -Sxpr sxpr_child0(Sxpr obj, Sxpr def); -Sxpr sxpr_child_value(Sxpr obj, Sxpr name, Sxpr def); - -/** Create a new atom. - * - * @param s atom name - * @return new atom - */ -static inline Sxpr mkatom(char *s){ - return atom_new(s); -} - -/** Create a new string sxpr. - * - * @param s string bytes (copied) - * @return new string - */ -static inline Sxpr mkstring(char *s){ - return string_new(s); -} - -/** Create an integer sxpr. - * - * @param i value - * @return sxpr - */ -static inline Sxpr mkint(int i){ - return OBJI(T_UINT, i); -} - -/** Create a boolean sxpr. - * - * @param b value - * @return sxpr - */ -static inline Sxpr mkbool(int b){ - return OBJI(T_BOOL, (b ? 1 : 0)); -} - -/* Constants used in parsing and printing. */ -#define k_list_open "(" -#define c_list_open '(' -#define k_list_close ")" -#define c_list_close ')' -#define k_true "true" -#define k_false "false" - -#define c_var '$' -#define c_escape '\\' -#define c_single_quote '\'' -#define c_double_quote '"' -#define c_string_open c_double_quote -#define c_string_close c_double_quote -#define c_data_open '[' -#define c_data_close ']' -#define c_binary '*' -#define c_eval '!' -#define c_concat_open '{' -#define c_concat_close '}' - -#endif /* ! _XEN_LIB_SXPR_H_ */ diff --git a/tools/lib/sxpr_parser.c b/tools/lib/sxpr_parser.c deleted file mode 100644 index 16fec56b67..0000000000 --- a/tools/lib/sxpr_parser.c +++ /dev/null @@ -1,897 +0,0 @@ - -#ifdef __KERNEL__ -# include -# include -# include -# include -# include -#else -# include -# include -#endif - -#include "iostream.h" -#include "lexis.h" -#include "sxpr_parser.h" -#include "sys_string.h" - -/** @file - * Sxpr parsing. - * - * So that the parser does not leak memory, all sxprs constructed by - * the parser must be freed on error. On successful parse the sxpr - * returned becomes the responsibility of the caller. - * - * @author Mike Wray - */ - -#define dprintf(fmt, args...) IOStream_print(iostdout, "[DEBUG] %s" fmt, __FUNCTION__, ##args) -#define printf(fmt, args...) IOStream_print(iostdout, fmt, ##args) - -static void reset(Parser *z); -static int inputchar(Parser *p, char c); -static int savechar(Parser *p, char c); -extern void parse_error(Parser *in); -extern void parse_error_id(Parser *in, ParseErrorId id); - -static int begin_start(Parser *p, char c); -static int state_start(Parser *p, char c); -static int end_start(Parser *p); - -static int begin_comment(Parser *p, char c); -static int state_comment(Parser *p, char c); -static int end_comment(Parser *p); - -static int begin_string(Parser *p, char c); -static int state_string(Parser *p, char c); -static int end_string(Parser *p); -static int state_escape(Parser *p, char c); -static int state_octal(Parser *p, char c); -static int state_hex(Parser *p, char c); - -static int begin_atom(Parser *p, char c); -static int state_atom(Parser *p, char c); -static int end_atom(Parser *p); - -static int state_list(Parser *p, char c); -static int begin_list(Parser *p, char c); -static int end_list(Parser *p); - -/** Print a parse error. - * - * @param in parser - * @param msg format followed by printf arguments - */ -void eprintf(Parser *in, char *msg, ...){ - va_list args; - if(in->error_out){ - va_start(args, msg); - IOStream_vprint(in->error_out, msg, args); - va_end(args); - } -} - -/** Print a parse warning. - * - * @param in parser - * @param msg format followed by printf arguments - */ -void wprintf(Parser *in, char *msg, ...){ - va_list args; - if(in->error_out){ - va_start(args, msg); - IOStream_vprint(in->error_out, msg, args); - va_end(args); - } -} - -/*============================================================================*/ - -/** Record defining the message for a parse error. */ -typedef struct { - ParseErrorId id; - char *message; -} ParseError; - -/** Format for printing parse error messages. */ -#define PARSE_ERR_FMT "parse error> line %3d, column %2d: %s" - -/** Message catalog for the parse error codes. */ -static ParseError catalog[] = { - { PARSE_ERR_UNSPECIFIED, "unspecified error" }, - { PARSE_ERR_NOMEM, "out of memory" }, - { PARSE_ERR_UNEXPECTED_EOF, "unexpected end of input" }, - { PARSE_ERR_TOKEN_TOO_LONG, "token too long" }, - { PARSE_ERR_INVALID_SYNTAX, "syntax error" }, - { PARSE_ERR_INVALID_ESCAPE, "invalid escape" }, - { 0, NULL } -}; - -/** Number of entries in the message catalog. */ -const static int catalog_n = sizeof(catalog)/sizeof(ParseError); - -void ParserState_free(ParserState *z){ - if(!z) return; - objfree(z->val); - deallocate(z); -} - -int ParserState_new(ParserStateFn *fn, ParserState *parent, ParserState **val){ - int err = 0; - ParserState *z; - z = ALLOCATE(ParserState); - if(z){ - z->fn = fn; - z->parent = parent; - z->val = ONULL; - } else { - err = -ENOMEM; - } - if(!err) *val = z; - return err; -} - -/** Free a parser. - * No-op if the parser is null. - * - * @param z parser - */ -void Parser_free(Parser *z){ - if(!z) return; - objfree(z->val); - z->val = ONONE; - deallocate(z); -} - -/** Create a new parser. The error stream defaults to null. - */ -Parser * Parser_new(void){ - Parser *z = ALLOCATE(Parser); - int err = -ENOMEM; - - if(!z) goto exit; - err = 0; - reset(z); - exit: - if(err){ - Parser_free(z); - z = NULL; - } - return z; -} - -/** Get the next character. - * Records the character read in the parser, - * and sets the line and character counts. - * - * @param p parser - * @return error flag: 0 on success, non-zero on error - */ -static int inputchar(Parser *p, char c){ - int err = 0; - if(c=='\n'){ - p->line_no++; - p->char_no = 0; - } else { - p->char_no++; - } - return err; -} - -static int savechar(Parser *p, char c){ - int err = 0; - if(p->buf_i >= p->buf_n){ - err = -ENOMEM; - goto exit; - } - p->buf[p->buf_i] = c; - p->buf_i++; - exit: - return err; -} - -int Parser_input_char(Parser *p, char c){ - int err = 0; - if(at_eof(p)){ - //skip; - } else { - inputchar(p, c); - } - if(!p->state){ - err = begin_start(p, c); - if(err) goto exit; - } - err = p->state->fn(p, c); - exit: - return err; -} - -int Parser_input_eof(Parser *p){ - int err = 0; - p->eof = 1; - err = Parser_input_char(p, IOSTREAM_EOF); - return err; -} - -int Parser_input(Parser *p, char *buf, int buf_n){ - int err = 0; - int i = 0; - if(buf_n <= 0){ - err = Parser_input_eof(p); - goto exit; - } - for(i = 0; istate, &p->state); - return err; -} - -int Parser_pop(Parser *p){ - int err = 0; - ParserState *s = p->state; - p->state = s->parent; - ParserState_free(s); - return err; -} - -int Parser_return(Parser *p){ - int err = 0; - Sxpr val = ONONE; - if(!p->state){ - err = -EINVAL; - goto exit; - } - val = p->state->val; - p->state->val = ONONE; - err = Parser_pop(p); - if(err) goto exit; - if(p->state){ - err = cons_push(&p->state->val, val); - } else { - val = nrev(val); - p->val = val; - } - exit: - if(err){ - objfree(val); - } - return err; -} - -/** Determine if a character is a separator. - * - * @param p parser - * @param c character to test - * @return 1 if a separator, 0 otherwise - */ -static int is_separator(Parser *p, char c){ - return in_sep_class(c); -} - -/** Return the current token. - * The return value points at the internal buffer, so - * it must not be modified (or freed). Use copy_token() if you need a copy. - * - * @param p parser - * @return token - */ -char *peek_token(Parser *p){ - return p->buf; -} - -/** Return a copy of the current token. - * The returned value should be freed when finished with. - * - * @param p parser - * @return copy of token - */ -char *copy_token(Parser *p){ - return strdup(peek_token(p)); -} - -static int do_intern(Parser *p){ - int err = 0; - Sxpr obj = intern(peek_token(p)); - if(NOMEMP(obj)){ - err = -ENOMEM; - } else { - p->state->val = obj; - } - return err; -} - -static int do_string(Parser *p){ - int err = 0; - Sxpr obj; - obj = string_new(peek_token(p)); - if(NOMEMP(obj)){ - err = -ENOMEM; - } else { - p->state->val = obj; - } - return err; -} - -void newtoken(Parser *p){ - memset(p->buf, 0, p->buf_n); - p->buf_i = 0; - p->tok_begin_line = p->line_no; - p->tok_begin_char = p->char_no; -} - -int get_escape(char c, char *d){ - int err = 0; - switch(c){ - case 'a': *d = '\a'; break; - case 'b': *d = '\b'; break; - case 'f': *d = '\f'; break; - case 'n': *d = '\n'; break; - case 'r': *d = '\r'; break; - case 't': *d = '\t'; break; - case 'v': *d = '\v'; break; - case c_escape: *d = c_escape; break; - case c_single_quote: *d = c_single_quote; break; - case c_double_quote: *d = c_double_quote; break; - default: - err = -EINVAL; - } - return err; -} - - -int begin_start(Parser *p, char c){ - return Parser_push(p, state_start); -} - -int state_start(Parser *p, char c){ - int err = 0; - if(at_eof(p)){ - err = end_start(p); - } else if(in_space_class(c)){ - //skip - } else if(in_comment_class(c)){ - begin_comment(p, c); - } else if(c == c_list_open){ - begin_list(p, c); - } else if(c == c_list_close){ - parse_error(p); - err = -EINVAL; - } else if(in_string_quote_class(c)){ - begin_string(p, c); - } else if(in_printable_class(c)){ - begin_atom(p, c); - } else if(c == 0x04){ - //ctrl-D, EOT: end-of-text. - Parser_input_eof(p); - } else { - parse_error(p); - err = -EINVAL; - } - return err; -} - -int end_start(Parser *p){ - int err = 0; - err = Parser_return(p); - return err; -} - -int begin_comment(Parser *p, char c){ - int err = 0; - err = Parser_push(p, state_comment); - if(err) goto exit; - err = inputchar(p, c); - exit: - return err; -} - -int state_comment(Parser *p, char c){ - int err = 0; - if(c == '\n' || at_eof(p)){ - err = end_comment(p); - } else { - err = inputchar(p, c); - } - return err; -} - -int end_comment(Parser *p){ - return Parser_pop(p); -} - -int begin_string(Parser *p, char c){ - int err = 0; - err = Parser_push(p, state_string); - if(err) goto exit; - newtoken(p); - p->state->delim = c; - exit: - return err; -} - -int state_string(Parser *p, char c){ - int err = 0; - if(at_eof(p)){ - parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF); - err = -EINVAL; - } else if(c == p->state->delim){ - err = end_string(p); - } else if(c == '\\'){ - err = Parser_push(p, state_escape); - } else { - err = savechar(p, c); - } - return err; -} - -int end_string(Parser *p){ - int err = 0; - err = do_string(p); - if(err) goto exit; - err = Parser_return(p); - exit: - return err; -} - -int state_escape(Parser *p, char c){ - int err = 0; - char d; - if(at_eof(p)){ - parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF); - err = -EINVAL; - goto exit; - } - if(get_escape(c, &d) == 0){ - err = savechar(p, d); - if(err) goto exit; - err = Parser_pop(p); - } else if(c == 'x'){ - p->state->fn = state_hex; - p->state->ival = 0; - p->state->count = 0; - } else { - p->state->fn = state_octal; - p->state->ival = 0; - p->state->count = 0; - err = Parser_input_char(p, c); - } - exit: - return err; -} - -int octaldone(Parser *p){ - int err = 0; - char d = (char)(p->state->ival & 0xff); - err = Parser_pop(p); - if(err) goto exit; - err = Parser_input_char(p, d); - exit: - return err; -} - -int octaldigit(Parser *p, char c){ - int err = 0; - p->state->ival *= 8; - p->state->ival += c - '0'; - p->state->count++; - if(err) goto exit; - if(p->state->ival < 0 || p->state->ival > 0xff){ - parse_error(p); - err = -EINVAL; - goto exit; - } - if(p->state->count == 3){ - err = octaldone(p); - } - exit: - return err; -} - -int state_octal(Parser *p, char c){ - int err = 0; - if(at_eof(p)){ - parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF); - err = -EINVAL; - goto exit; - } else if('0' <= c && c <= '7'){ - err = octaldigit(p, c); - } else { - err = octaldone(p); - if(err) goto exit; - Parser_input_char(p, c); - } - exit: - return err; -} - -int hexdone(Parser *p){ - int err = 0; - char d = (char)(p->state->ival & 0xff); - err = Parser_pop(p); - if(err) goto exit; - err = Parser_input_char(p, d); - exit: - return err; -} - -int hexdigit(Parser *p, char c, char d){ - int err = 0; - p->state->ival *= 16; - p->state->ival += c - d; - p->state->count++; - if(err) goto exit; - if(p->state->ival < 0 || p->state->ival > 0xff){ - parse_error(p); - err = -EINVAL; - goto exit; - } - if(p->state->count == 2){ - err = hexdone(p); - } - exit: - return err; -} - -int state_hex(Parser *p, char c){ - int err = 0; - if(at_eof(p)){ - parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF); - err = -EINVAL; - goto exit; - } else if('0' <= c && c <= '9'){ - err = hexdigit(p, c, '0'); - } else if('A' <= c && c <= 'F'){ - err = hexdigit(p, c, 'A'); - } else if('a' <= c && c <= 'f'){ - err = hexdigit(p, c, 'a'); - } else if(p->state->count){ - err =hexdone(p); - if(err) goto exit; - Parser_input_char(p, c); - } - exit: - return err; -} - -int begin_atom(Parser *p, char c){ - int err = 0; - err = Parser_push(p, state_atom); - if(err) goto exit; - newtoken(p); - err = savechar(p, c); - exit: - return err; -} - -int state_atom(Parser *p, char c){ - int err = 0; - if(at_eof(p)){ - err = end_atom(p); - } else if(is_separator(p, c) || - in_space_class(c) || - in_comment_class(c)){ - err = end_atom(p); - if(err) goto exit; - err = Parser_input_char(p, c); - } else { - err = savechar(p, c); - } - exit: - return err; -} - -int end_atom(Parser *p){ - int err = 0; - err = do_intern(p); - if(err) goto exit; - err = Parser_return(p); - exit: - return err; -} - -int state_list(Parser *p, char c){ - int err = 0; - if(at_eof(p)){ - parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF); - err = -EINVAL; - } else if(c == c_list_close){ - p->state->val = nrev(p->state->val); - err = end_list(p); - } else { - err = state_start(p, c); - } - return err; - -} - -int begin_list(Parser *p, char c){ - return Parser_push(p, state_list); -} - -int end_list(Parser *p){ - return Parser_return(p); -} - -/** Reset the fields of a parser to initial values. - * - * @param z parser - */ -static void reset(Parser *z){ - IOStream *error_out = z->error_out; - int flags = z->flags; - zero(z, sizeof(Parser)); - z->buf_n = sizeof(z->buf) - 1; - z->buf_i = 0; - z->line_no = 1; - z->char_no = 0; - z->error_out = error_out; - z->flags = flags; -} - -/** Set the parser error stream. - * Parse errors are reported on the the error stream if it is non-null. - * - * @param z parser - * @param error_out error stream - */ -void set_error_stream(Parser *z, IOStream *error_out){ - if(z){ - z->error_out = error_out; - } -} - -/** Get the parser error message for an error code. - * - * @param id error code - * @return error message (empty string if the code is unknown) - */ -static char *get_message(ParseErrorId id){ - int i; - for(i=0; iline_no; -} - -/** Get the column number. - * - * @param in parser - */ -int get_column(Parser *in){ - return in->char_no; -} - -/** Get the line number the current token started on. - * - * @param in parser - */ -int get_tok_line(Parser *in){ - return in->tok_begin_line; -} - -/** Get the column number the current token started on. - * - * @param in parser - */ -int get_tok_column(Parser *in){ - return in->tok_begin_char; -} - -/** Report a parse error. - * Does nothing if the error stream is null or there is no error. - * - * @param in parser - */ -static void report_error(Parser *in){ - if(in->error_out && in->err){ - char *msg = get_message(in->err); - char *tok = peek_token(in); - IOStream_print(in->error_out, PARSE_ERR_FMT, - get_tok_line(in), get_tok_column(in), msg); - if(tok && tok[0]){ - IOStream_print(in->error_out, " '%s'", tok); - } - IOStream_print(in->error_out, "\n"); - } -} - -/** Get the error message for the current parse error code. - * Does nothing if there is no error. - * - * @param in parser - * @param buf where to place the message - * @param n maximum number of characters to place in buf - * @return current error code (zero for no error) - */ -int parse_error_message(Parser *in, char *buf, int n){ - if(in->err){ - char *msg = get_message(in->err); - snprintf(buf, n, PARSE_ERR_FMT, get_tok_line(in), get_tok_column(in), msg); - } - return in->err; -} - -/** Flag an unspecified parse error. All subsequent reads will fail. - * - * @param in parser - */ -void parse_error(Parser *in){ - parse_error_id(in, PARSE_ERR_INVALID_SYNTAX); -} - -/** Flag a parse error. All subsequent reads will fail. - * Does not change the parser error code if it is already set. - * - * @param in parser - * @param id error code - */ -void parse_error_id(Parser *in, ParseErrorId id){ - if(!in->err){ - in->err = id; - report_error(in); - } -} - -/** Test if the parser's error flag is set. - * - * @param in parser - * @return 1 if set, 0 otherwise - */ -int has_error(Parser *in){ - return (in->err > 0); -} - -/** Test if the parser is at end of input. - * - * @param in parser - * @return 1 if at EOF, 0 otherwise - */ -int at_eof(Parser *p){ - return p->eof; -} - -#ifdef SXPR_PARSER_MAIN -/* Stuff for standalone testing. */ - -#include "file_stream.h" -#include "string_stream.h" - -int stringof(Sxpr exp, char **s){ - int err = 0; - if(ATOMP(exp)){ - *s = atom_name(exp); - } else if(STRINGP(exp)){ - *s = string_string(exp); - } else { - err = -EINVAL; - *s = NULL; - } - return err; -} - -int child_string(Sxpr exp, Sxpr key, char **s){ - int err = 0; - Sxpr val = sxpr_child_value(exp, key, ONONE); - err = stringof(val, s); - return err; -} - -int intof(Sxpr exp, int *v){ - int err = 0; - char *s; - unsigned long l; - if(INTP(exp)){ - *v = OBJ_INT(exp); - } else { - err = stringof(exp, &s); - if(err) goto exit; - err = convert_atoul(s, &l); - *v = (int)l; - } - exit: - return err; -} - -int child_int(Sxpr exp, Sxpr key, int *v){ - int err = 0; - Sxpr val = sxpr_child_value(exp, key, ONONE); - err = intof(val, v); - return err; -} - -int eval_vnet(Sxpr exp){ - int err = 0; - Sxpr oid = intern("id"); - int id; - err = child_int(exp, oid, &id); - if(err) goto exit; - dprintf("> vnet id=%d\n", id); - exit: - dprintf("< err=%d\n", err); - return err; -} - -int eval_connect(Sxpr exp){ - int err = 0; - Sxpr ovif = intern("vif"); - Sxpr ovnet = intern("vnet"); - char *vif; - int vnet; - - err = child_string(exp, ovif, &vif); - if(err) goto exit; - err = child_int(exp, ovnet, &vnet); - if(err) goto exit; - dprintf("> connect vif=%s vnet=%d\n", vif, vnet); - exit: - dprintf("< err=%d\n", err); - return err; -} - -int eval(Sxpr exp){ - int err = 0; - Sxpr oconnect = intern("connect"); - Sxpr ovnet = intern("vnet"); - - if(sxpr_elementp(exp, ovnet)){ - err = eval_vnet(exp); - } else if(sxpr_elementp(exp, oconnect)){ - err = eval_connect(exp); - } else { - err = -EINVAL; - } - return err; -} - -/** Main program for testing. - * Parses input and prints it. - * - * @param argc number of arguments - * @param argv arguments - * @return error code - */ -int main(int argc, char *argv[]){ - Parser *pin; - int err = 0; - char buf[1024]; - int k; - Sxpr obj, l, x; - - pin = Parser_new(); - set_error_stream(pin, iostdout); - dprintf("> parse...\n"); - while(1){ - k = fread(buf, 1, 1024, stdin); - err = Parser_input(pin, buf, k); - dprintf("> Parser_input=%d\n", err); - if(k <= 0) break; - } - obj = pin->val; - for(l = obj ; CONSP(l); l = CDR(l)){ - x = CAR(l); - objprint(iostdout, x, 0); printf("\n"); - eval(x); - } - dprintf("> err=%d\n", err); - return 0; -} -#endif diff --git a/tools/lib/sxpr_parser.h b/tools/lib/sxpr_parser.h deleted file mode 100644 index 7296312e44..0000000000 --- a/tools/lib/sxpr_parser.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of the - * License, or (at your option) any later version. This library is - * distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _XEN_LIB_SXPR_PARSER_H_ -#define _XEN_LIB_SXPR_PARSER_H_ - -#include "sxpr.h" -#include "iostream.h" - -/** @file - * Sxpr parsing definitions. - */ - -/** Size of a parser input buffer. - * Tokens read must fit into this size (including trailing null). - */ -#define PARSER_BUF_SIZE 1024 - -struct Parser; -typedef int ParserStateFn(struct Parser *, char c); - -typedef struct ParserState { - struct ParserState *parent; - Sxpr val; - int ival; - int count; - char delim; - ParserStateFn *fn; -} ParserState; - -/** Structure representing an input source for the parser. - * Can read from any IOStream implementation. - */ -typedef struct Parser { - Sxpr val; - /** Error reporting stream (null for no reports). */ - IOStream *error_out; - int eof; - /** Error flag. Non-zero if there has been a read error. */ - int err; - /** Line number on input (from 1). */ - int line_no; - /** Column number of input (reset on new line). */ - int char_no; - /** Lookahead character. */ - char c; - /** Buffer for reading tokens. */ - char buf[PARSER_BUF_SIZE]; - /** Size of token buffer. */ - int buf_n; - int buf_i; - /** Line the last token started on. */ - int tok_begin_line; - /** Character number the last token started on. */ - int tok_begin_char; - /** Parsing flags. */ - int flags; - ParserState *state; -} Parser; - -/** Parser error codes. */ -typedef enum { - PARSE_ERR_NONE=0, - PARSE_ERR_UNSPECIFIED, - PARSE_ERR_NOMEM, - PARSE_ERR_UNEXPECTED_EOF, - PARSE_ERR_TOKEN_TOO_LONG, - PARSE_ERR_INVALID_SYNTAX, - PARSE_ERR_INVALID_ESCAPE, -} ParseErrorId; - - -/** Parser flags. */ -//enum { -//}; - -/** Raise some parser flags. - * - * @param in parser - * @param flags flags mask - */ -inline static void parser_flags_raise(Parser *in, int flags){ - in->flags |= flags; -} - -/** Lower some parser flags. - * - * @param in parser - * @param flags flags mask - */ -inline static void parser_flags_lower(Parser *in, int flags){ - in->flags &= ~flags; -} - -/** Clear all parser flags. - * - * @param in parser - */ -inline static void parser_flags_clear(Parser *in){ - in->flags = 0; -} - -extern void Parser_free(Parser *z); -extern Parser * Parser_new(void); -extern int Parser_input(Parser *p, char *buf, int buf_n); -extern int Parser_input_eof(Parser *p); - -extern int parse_error_message(Parser *in, char *buf, int n); -extern int has_error(Parser *in); -extern int at_eof(Parser *in); - -#endif /* ! _XEN_LIB_SXPR_PARSER_H_ */ diff --git a/tools/lib/sys_ctype.h b/tools/lib/sys_ctype.h deleted file mode 100644 index 1dc6cf2fac..0000000000 --- a/tools/lib/sys_ctype.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _XENO_SYS_CTYPE_H_ -#define _XENO_SYS_CTYPE_H_ -/** @file - ** Replacement for ctype include that can be used - * from user or kernel code. - */ -#ifdef __KERNEL__ -# include -#else -# include -#endif -#endif /* ! _XENO_SYS_CTYPE_H_ */ diff --git a/tools/lib/sys_net.c b/tools/lib/sys_net.c deleted file mode 100644 index 0e7ac5d638..0000000000 --- a/tools/lib/sys_net.c +++ /dev/null @@ -1,309 +0,0 @@ -/* - * Copyright (C) 2001 - 2004 Mike Wray - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of the - * License, or (at your option) any later version. This library is - * distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "sys_net.h" -#include "sys_string.h" - -/** @file - * All network data are kept in network order and only converted to - * host order for display. Network data includes IP addresses, port numbers and - * network masks. - */ - -/** Maximum value for a port. */ -#define PORT_MAX 0xffff - -/** Convert a number of bits to a network mask - * for IP addresses. The number of bits must - * be in the range 1-31. - * - * @param n number of bits to set in the mask - * @return value with n high bits set (in network order) - */ -unsigned long bits_to_mask(int n){ - unsigned long mask = (n ? (1 << 31) : 0); - int i; - for(i=1; i> 1); - } - return htonl(mask); -} - -/** Convert a network mask to a number of bits. - * - * @param mask network mask in network order - * @return number of bits in mask - */ -int mask_to_bits(unsigned long mask){ - // Start with n set to the number of bits in the mask. Then reduce n by - // the number of low zero bits in the mask. - int n = 32; - for(mask = ntohl(mask); - (mask & 1)==0 && n>0; - mask >>= 1){ - n--; - } - return n; -} - -/** Get the index of the first occurrence of a character in a string. - * Stops at end of string or after n characters. - * - * @param s input string - * @param n maximum number of charactes to search - * @param c character to look for - * @return index of first occurrence, -1 if not found - */ -inline static int indexof(const char *s, int n, char c){ - int i; - for(i=0; i= sizeof(buf)){ - goto exit; - } - for(i=0; i < WORD_BYTES; i++){ - int idx = indexof(s, n, dot); - idx = (idx < 0 ? strlen(s) : idx); - strncpy(buf, s, idx); buf[idx]='\0'; - if(convert_atoul(buf, &v)){ - goto exit; - } - if(v < 0 || v > ADDR_MAX){ - goto exit; - } - addr |= (v << shift); - if(idx == n) break; - shift -= BYTE_BITS; - s += idx+1; - } - err = 0; - exit: - addr = htonl(addr); - *address = (err ? 0 : addr); - return err; -} - -#ifdef __KERNEL__ -/** Convert an address in network order to IPv4 dot notation. - * The return value is a static buffer which is overwritten on each call. - * - * @param inaddr address (in network order) - * @return address in dot notation - */ -char *inet_ntoa(struct in_addr inaddr){ - static char address[16] = {}; - uint32_t addr = ntohl(inaddr.s_addr); - snprintf(address, sizeof(address), "%d.%d.%d.%d", - (unsigned)((addr >> 24) & 0xff), - (unsigned)((addr >> 16) & 0xff), - (unsigned)((addr >> 8) & 0xff), - (unsigned)((addr ) & 0xff)); - return address; -} - - -/** Convert a string in IPv4 dot notation to an int in network order. - * - * @param address address in dot notation - * @param inp result of conversion (in network order) - * @return 0 on success, error code on error - */ -int inet_aton(const char *address, struct in_addr *inp){ - int err = 0; - unsigned long addr; - - err = get_inet_addr(address, &addr); - if(err) goto exit; - inp->s_addr = addr; - exit: - return err; -} -#endif - -/** Convert a hostname or IPv4 address string to an address in network order. - * - * @param name input hostname or address string - * @param address where to put the address - * @return 1 if address found OK, 0 otherwise - */ -int get_host_address(const char *name, unsigned long *address){ -#ifdef __KERNEL__ - return get_inet_addr(name, address) == 0; -#else - struct hostent *host = gethostbyname(name); - if(!host){ - return 0; - } - *address = ((struct in_addr *)(host->h_addr))->s_addr; - return 1; -#endif -} - -/** Convert a service name to a port (in network order). - * - * @param name service name - * @param port where to put the port - * @return 1 if service port found OK, 0 otherwise - */ -int get_service_port(const char *name, unsigned long *port){ -#ifdef __KERNEL__ - return 0; -#else - struct servent *service; - service = getservbyname(name, 0); - if(!service){ - return 0; - } - *port = service->s_port; - return 1; -#endif -} - -/** Convert a port number (in network order) to a service name. - * - * @param port the port number - * @return service name if found OK, 0 otherwise - */ -char *get_port_service(unsigned long port){ -#ifdef __KERNEL__ - return 0; -#else - struct servent *service = getservbyport(port, 0); - return (service ? service->s_name : 0); -#endif -} - -/** Convert a decimal integer or service name to a port (in network order). - * - * @param s input to convert - * @param port where to put the port - * @return 1 if port found OK, 0 otherwise - */ -int convert_service_to_port(const char *s, unsigned long *port){ - int ok = 0; - unsigned long value; - if(convert_atoul(s, &value)){ - ok = get_service_port(s, &value); - } else { - ok = (0 <= value) && (value <= PORT_MAX); - value = htons((unsigned short)value); - } - *port = (ok ? value : 0); - return ok; -} - -#define MAC_ELEMENT_N 6 // Number of elements in a MAC address. -#define MAC_DIGIT_N 2 // Number of digits in an element in a MAC address. -#define MAC_LENGTH 17 //((MAC_ELEMENT_N * MAC_DIGIT_N) + MAC_ELEMENT_N - 1) - -/** Convert a mac address from a string of the form - * XX:XX:XX:XX:XX:XX to numerical form (an array of 6 unsigned chars). - * Each X denotes a hex digit: 0..9, a..f, A..F. - * Also supports using '-' as the separator instead of ':'. - * - * @param mac_in string to convert - * @param mac destination for the value - * @return 0 on success, -1 on error - */ -int mac_aton(const char *mac_in, unsigned char *mac){ - int err = 0; - int i, j; - const char *p; - char sep = 0; - unsigned char d; - if(!mac_in || strlen(mac_in) != MAC_LENGTH){ - err = -1; - goto exit; - } - for(i = 0, p = mac_in; i < MAC_ELEMENT_N; i++){ - d = 0; - if(i){ - if(!sep){ - if(*p == ':' || *p == '-') sep = *p; - } - if(sep && *p == sep){ - p++; - } else { - err = -1; - goto exit; - } - } - for(j = 0; j < MAC_DIGIT_N; j++, p++){ - if(j) d <<= 4; - if(*p >= '0' && *p <= '9'){ - d += (*p - '0'); - } else if(*p >= 'A' && *p <= 'F'){ - d += (*p - 'A') + 10; - } else if(*p >= 'a' && *p <= 'f'){ - d += (*p - 'a') + 10; - } else { - err = -1; - goto exit; - } - } - mac[i] = d; - } - exit: - return err; -} - -/** Convert a MAC address from numerical form to a string. - * - * @param mac address to convert - * @return static string value - */ -char *mac_ntoa(const unsigned char *mac){ - static char buf[MAC_LENGTH + 1]; - int buf_n = sizeof(buf); - - memset(buf, buf_n, 0); - snprintf(buf, buf_n, "%02x:%02x:%02x:%02x:%02x:%02x", - mac[0], mac[1], mac[2], - mac[3], mac[4], mac[5]); - buf[buf_n - 1] = '\0'; - return buf; -} diff --git a/tools/lib/sys_net.h b/tools/lib/sys_net.h deleted file mode 100644 index da6c1e8fd5..0000000000 --- a/tools/lib/sys_net.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2001 - 2004 Mike Wray - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _XEN_LIB_SYS_NET_H_ -#define _XEN_LIB_SYS_NET_H_ -/** @file - * - * Replacement for standard network includes. - * Works in user or kernel code. - */ - -extern int get_inet_addr(const char *s, unsigned long *address); -extern unsigned long bits_to_mask(int n); -extern int mask_to_bits(unsigned long mask); -extern int get_host_address(const char *name, unsigned long *address); -extern int get_service_port(const char *name, unsigned long *port); -extern char *get_port_service(unsigned long port); -extern int convert_service_to_port(const char *s, unsigned long *port); - -#ifdef __KERNEL__ -#include -#include -#include -#include -#include - -#ifndef htonl -#define htonl(x) __constant_htonl(x) -#endif - -#ifndef ntohl -#define ntohl(x) __constant_ntohl(x) -#endif - -#ifndef htons -#define htons(x) __constant_htons(x) -#endif - -#ifndef ntohs -#define ntohs(x) __constant_ntohs(x) -#endif - -#include -extern char *inet_ntoa(struct in_addr inaddr); -extern int inet_aton(const char *address, struct in_addr *inp); - -#else - -#include -#include -#include -#include -#include - -#endif - -extern char *mac_ntoa(const unsigned char *macaddr); -extern int mac_aton(const char *addr, unsigned char *macaddr); - -#endif /* !_SP_SYS_NET_H_ */ - - - diff --git a/tools/lib/sys_string.c b/tools/lib/sys_string.c deleted file mode 100644 index 13a90dfd7d..0000000000 --- a/tools/lib/sys_string.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (C) 2001 - 2004 Mike Wray - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifdef __KERNEL__ -# include -# include -# include -# include -#else -# include -#endif - -#include "allocate.h" -#include "sys_string.h" - -/** Set the base to use for converting a string to a number. Base is - * hex if starts with 0x, otherwise decimal. - * - * @param s input string - * @param base where to put the base - * @return rest of s to parse as a number - */ -inline static const char * convert_set_base(const char *s, int *base){ - *base = 10; - if(s){ - if(*s=='0'){ - s++; - if(*s=='x' || *s=='X'){ - *base = 16; - s++; - } - } - } - return s; -} - -/** Get the numerical value of a digit in the given base. - * - * @param c digit character - * @param base to use - * @return numerical value of digit in range 0..base-1 or - * -1 if not in range for the base - */ -inline static int convert_get_digit(char c, int base){ - int d; - - if('0'<=c && c<='9'){ - d = c - '0'; - } else if('a'<=c && c<='f'){ - d = c - 'a' + 10; - } else if('A'<=c && c<='F'){ - d = c - 'A' + 10; - } else { - d = -1; - } - return (d < base ? d : -1); -} - -/** Convert a string to an unsigned long by parsing it as a number. - * Will accept hex or decimal in usual C syntax. - * - * @param str input string - * @param val where to put the result - * @return 0 if converted OK, negative otherwise - */ -int convert_atoul(const char *str, unsigned long *val){ - int err = 0; - unsigned long v = 0; - int base; - const char *s = str; - - if(!s) { - err = -EINVAL; - goto exit; - } - s = convert_set_base(s, &base); - for( ; !err && *s; s++){ - int digit = convert_get_digit(*s, base); - if(digit<0){ - err = -EINVAL; - goto exit; - } - v *= base; - v += digit; - } - exit: - *val = (err ? 0 : v); - return err; -} - -/** Combine a directory path with a relative path to produce - * a new path. - * - * @param s directory path - * @param t relative path - * @return new combined path s/t - */ -int path_concat(char *s, char *t, char **val){ - int err = 0; - int sn, tn, vn; - char *v; - sn = strlen(s); - if(sn > 0 && s[sn-1] == '/'){ - sn--; - } - tn = strlen(t); - if(tn > 0 && t[0] == '/'){ - tn--; - } - vn = sn+tn+1; - v = (char*)allocate(vn+1); - if(!v){ - err = -ENOMEM; - goto exit; - } - strncpy(v, s, sn); - v[sn] = '/'; - strncpy(v+sn+1, t, tn); - v[vn] = '\0'; - exit: - *val = (err ? NULL : v); - return err; -} diff --git a/tools/lib/sys_string.h b/tools/lib/sys_string.h deleted file mode 100644 index f39935f669..0000000000 --- a/tools/lib/sys_string.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2001 - 2004 Mike Wray - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _XEN_LIB_SYS_STRING_H_ -#define _XEN_LIB_SYS_STRING_H_ -/** @file - * Replacement for standard string includes. - * Works in user or kernel code. - */ -/*============================================================================*/ -#ifdef __KERNEL__ - -#include -#include -#include -#include -#include -#include "allocate.h" - -#if 0 -static inline int tolower(int c){ - return (c>='A' && c<='Z' ? (c-'A')+'a' : c); -} -#endif - -static inline int isalpha(int c){ - return (c>='A' && c<='Z') || (c>='a' && c<='z'); -} - -static inline int isdigit(int c){ - return (c>='0' && c<='9'); -} - -#if 0 -static inline int strcasecmp(const char *s1, const char *s2){ - int c1, c2; - - do { - c1 = tolower(*s1++); - c2 = tolower(*s2++); - } while (c1 && c1 == c2); - return c1 - c2; -} -#endif - -static inline char * strdup(const char *s){ - int n = (s ? 1+strlen(s) : 0); - char *copy = (n ? allocate(n) : NULL); - if(copy){ - strcpy(copy, s); - } - return copy; -} - -/*============================================================================*/ -#else -#include -#include - -#ifndef _GNU_SOURCE -static inline size_t strnlen(const char *s, size_t n){ - int k = 0; - if(s){ - for(k=0; *s && k -/** @file - * XDR packer/unpacker for elements. - * - * string -> [T_STRING] [len:u32] - * atom -> [T_ATOM] [len:u32] - * uint -> [T_UINT] [value] - * cons -> [T_CONS] - * null -> [T_NULL] - * none -> [T_NONE] - * bool -> [T_BOOL] { 0:u8 | 1:u8 } - * - * types packed as u16. - * - * So (a b c) -> [T_CONS] a [T_CONS] b [T_CONS] c [T_NULL] - * () -> [T_NULL] - */ - -int pack_bool(IOStream *io, int x){ - int err=0; - err = IOStream_print(io, "%c", 0xff & x); - if(err > 0) err = 0; - return err; -} - -int unpack_bool(IOStream *io, int *x){ - int err = 0; - int c; - c = IOStream_getc(io); - *x = (c < 0 ? 0 : c); - err = IOStream_error(io); - if(c < 0 && !err) err = -EIO; - return err; -} - -int pack_ushort(IOStream *io, unsigned short x){ - int err=0; - err = IOStream_print(io, "%c%c", - 0xff & (x >> 8), - 0xff & (x )); - if(err > 0) err = 0; - return err; -} - -int unpack_ushort(IOStream *io, unsigned short *x){ - int err = 0; - int i, c = 0; - *x = 0; - for(i = 0; i< 2; i++){ - c = IOStream_getc(io); - if(c < 0) break; - *x <<= 8; - *x |= (0xff & c); - } - err = IOStream_error(io); - if(c < 0 && !err) err = -EIO; - return err; -} - -int pack_uint(IOStream *io, unsigned int x){ - int err=0; - err = IOStream_print(io, "%c%c%c%c", - 0xff & (x >> 24), - 0xff & (x >> 16), - 0xff & (x >> 8), - 0xff & (x )); - if(err > 0) err = 0; - return err; -} - -int unpack_uint(IOStream *io, unsigned int *x){ - int err = 0; - int i, c = 0; - *x = 0; - for(i = 0; i< 4; i++){ - c = IOStream_getc(io); - if(c < 0) break; - *x <<= 8; - *x |= (0xff & c); - } - err = IOStream_error(io); - if(c < 0 && !err) err = -EIO; - return err; -} - -int pack_string(IOStream *io, Sxpr x){ - int err = 0; - int n = string_length(x); - char *s = string_string(x); - int i; - err = pack_uint(io, n); - if(err) goto exit; - for(i = 0; i < n; i++){ - err = IOStream_print(io, "%c", s[i]); - if(err < 0) break; - } - if(err > 0) err = 0; - exit: - return err; -} - -int unpack_string(IOStream *io, Sxpr *x){ - int err; - unsigned int n; - int i, c = 0; - char *s; - Sxpr val = ONONE; - - err = unpack_uint(io, &n); - if(err) goto exit; - val = halloc(n+1, T_STRING); - if(NOMEMP(val)){ - err = -ENOMEM; - goto exit; - } - s = string_string(val); - for(i=0; iname); - break; - case T_STRING: - err = pack_string(io, x); - break; - case T_UINT: - err = pack_uint(io, get_ul(x)); - break; - default: - err = -EINVAL; - IOStream_print(iostderr, "%s> invalid type %d\n", __FUNCTION__, type); - break; - } - exit: - return err; -} - -int unpack_sxpr(IOStream *io, Sxpr *x){ - int err = 0; - unsigned short type; - unsigned int u; - Sxpr val = ONONE, y; - - err = unpack_ushort(io, &type); - if(err) goto exit; - switch(type){ - case T_NULL: - val = ONULL; - break; - case T_NONE: - val = ONONE; - break; - case T_CONS: - err = unpack_cons(io, &val); - break; - case T_BOOL: - err = unpack_bool(io, &u); - if(err) goto exit; - val = (u ? OTRUE : OFALSE); - break; - case T_ATOM: - err = unpack_string(io, &y); - if(err) goto exit; - val = intern(string_string(y)); - objfree(y); - break; - case T_STRING: - err = unpack_string(io, &val); - break; - case T_UINT: - err = unpack_uint(io, &u); - if(err) goto exit; - val = OBJI(type, u); - break; - default: - err = -EINVAL; - IOStream_print(iostderr, "%s> invalid type %d\n", __FUNCTION__, type); - break; - } - exit: - *x = (err ? ONONE : val); - return err; -} diff --git a/tools/lib/xdr.h b/tools/lib/xdr.h deleted file mode 100644 index cb7d97df95..0000000000 --- a/tools/lib/xdr.h +++ /dev/null @@ -1,14 +0,0 @@ -/* $Id: xdr.h,v 1.2 2003/09/29 13:40:00 mjw Exp $ */ -#ifndef _SP_XDR_H_ -#define _SP_XDR_H_ -#include "iostream.h" -#include "sxpr.h" -int pack_uint(IOStream *out, unsigned int x); -int unpack_uint(IOStream *in, unsigned int *x); -int pack_string(IOStream *out, Sxpr x); -int unpack_string(IOStream *in, Sxpr *x); -int pack_cons(IOStream *out, Sxpr x); -int unpack_cons(IOStream *in, Sxpr *x); -int pack_sxpr(IOStream *out, Sxpr x); -int unpack_sxpr(IOStream *in, Sxpr *x); -#endif /* _SP_XDR_H_ */ diff --git a/tools/libxc/Makefile b/tools/libxc/Makefile new file mode 100644 index 0000000000..8db55c2028 --- /dev/null +++ b/tools/libxc/Makefile @@ -0,0 +1,115 @@ + +MAJOR = 1.3 +MINOR = 0 +SONAME = libxc.so.$(MAJOR) + +CC = gcc + +XEN_ROOT = ../.. +include $(XEN_ROOT)/tools/Make.defs + +vpath %.h $(XEN_HYPERVISOR_IFS) +INCLUDES += -I $(XEN_HYPERVISOR_IFS) + +vpath %h $(XEN_LINUX_INCLUDE) +INCLUDES += -I $(XEN_LINUX_INCLUDE) + +vpath %.h $(XEN_XU) +INCLUDES += -I $(XEN_XU) + +vpath %c $(XEN_LIBXUTIL) +INCLUDES += -I $(XEN_LIBXUTIL) + +LIB_SRCS := +LIB_SRCS += allocate.c +#LIB_SRCS += enum.c +LIB_SRCS += file_stream.c +LIB_SRCS += gzip_stream.c +#LIB_SRCS += hash_table.c +LIB_SRCS += iostream.c +#LIB_SRCS += kernel_stream.c +#LIB_SRCS += lexis.c +#LIB_SRCS += lzi_stream.c +#LIB_SRCS += lzo_stream.c +#LIB_SRCS += marshal.c +#LIB_SRCS += socket_stream.c +#LIB_SRCS += string_stream.c +#LIB_SRCS += sxpr.c +#LIB_SRCS += sxpr_parser.c +LIB_SRCS += sys_net.c +LIB_SRCS += sys_string.c +#LIB_SRCS += xdr.c + +SRCS := +SRCS += xc_atropos.c +SRCS += xc_bvtsched.c +SRCS += xc_domain.c +SRCS += xc_evtchn.c +SRCS += xc_io.c +SRCS += xc_linux_build.c +SRCS += xc_linux_restore.c +SRCS += xc_linux_save.c +SRCS += xc_misc.c +SRCS += xc_netbsd_build.c +SRCS += xc_physdev.c +SRCS += xc_private.c +SRCS += xc_rrobin.c + +#SRCS += $(LIB_SRCS) + +CFLAGS += -Wall +CFLAGS += -Werror +CFLAGS += -g +CFLAGS += -O3 +CFLAGS += -fno-strict-aliasing +CFLAGS += $(INCLUDES) +# Get gcc to generate the dependencies for us. +CFLAGS += -Wp,-MD,.$(@F).d +DEPS = .*.d + +OBJS = $(patsubst %.c,%.o,$(SRCS)) + +LIB = libxc.so libxc.so.$(MAJOR) libxc.so.$(MAJOR).$(MINOR) + +all: check-for-zlib $(LIB) + +check-for-zlib: + @if [ ! -e /usr/include/zlib.h ]; then \ + echo "***********************************************************"; \ + echo "ERROR: install zlib header files (http://www.gzip.org/zlib)"; \ + echo "***********************************************************"; \ + false; \ + fi + +install: all + mkdir -p $(prefix)/usr/lib + mkdir -p $(prefix)/usr/include + install -m0755 $(LIB) $(prefix)/usr/lib + install -m0644 xc.h $(prefix)/usr/include + +clean: + $(RM) *.a *.so *.o *.rpm $(LIB) + $(RM) *~ + $(RM) $(DEPS) + +rpm: all + rm -rf staging + mkdir staging + mkdir staging/i386 + rpmbuild --define "staging$$PWD/staging" --define '_builddir.' \ + --define "_rpmdir$$PWD/staging" -bb rpm.spec + mv staging/i386/*.rpm . + rm -rf staging + +libxc.so: + ln -sf libxc.so.$(MAJOR) $@ +libxc.so.$(MAJOR): + ln -sf libxc.so.$(MAJOR).$(MINOR) $@ +libxc.so.$(MAJOR).$(MINOR): $(OBJS) + $(CC) -Wl,-soname -Wl,$(SONAME) -shared -o $@ $^ ../libxutil/libxutil.a -lz + +%.o: %.c Makefile + +# $(CC) $(CFLAGS) -o $@ $< + +-include $(DEPS) diff --git a/tools/libxc/rpm.spec b/tools/libxc/rpm.spec new file mode 100644 index 0000000000..1b4c5fc85a --- /dev/null +++ b/tools/libxc/rpm.spec @@ -0,0 +1,28 @@ +Summary: Xen control interface library +Name: xen-internal-library +Version: 1.2 +Release: 1 +License: Xen +Group: Xen +BuildRoot: %{staging} +%description +Library to make it easier to access the Xen control interfaces. + +%pre +%preun +%install +install -m 0755 -d $RPM_BUILD_ROOT/lib +install -m 0755 libxc.a $RPM_BUILD_ROOT/lib/libxc.a +install -m 0755 libxc.so $RPM_BUILD_ROOT/lib/libxc.so +install -m 0755 -d $RPM_BUILD_ROOT/include +install -m 0644 xc.h $RPM_BUILD_ROOT/include/xc.h +%clean +%post +%postun +%files +%defattr(-,root,root) +%dir /lib +/lib/libxc.a +/lib/libxc.so +%dir /include +/include/xc.h diff --git a/tools/libxc/xc.h b/tools/libxc/xc.h new file mode 100644 index 0000000000..f9692607bd --- /dev/null +++ b/tools/libxc/xc.h @@ -0,0 +1,203 @@ +/****************************************************************************** + * xc.h + * + * A library for low-level access to the Xen control interfaces. + * + * Copyright (c) 2003, K A Fraser. + */ + +#ifndef __XC_H__ +#define __XC_H__ + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned long u32; +typedef unsigned long long u64; +typedef signed char s8; +typedef signed short s16; +typedef signed long s32; +typedef signed long long s64; + +/* Obtain or relinquish a handle on the 'xc' library. */ +int xc_interface_open(void); +int xc_interface_close(int xc_handle); + +typedef struct { + u32 domid; + unsigned int cpu; + unsigned int dying:1, crashed:1, shutdown:1, + paused:1, blocked:1, running:1; + unsigned int shutdown_reason; /* only meaningful if shutdown==1 */ + unsigned long nr_pages; + unsigned long shared_info_frame; + u64 cpu_time; +#define XC_DOMINFO_MAXNAME 16 + char name[XC_DOMINFO_MAXNAME]; + unsigned long max_memkb; +} xc_dominfo_t; + +typedef struct xc_shadow_control_stats_st +{ + unsigned long fault_count; + unsigned long dirty_count; + unsigned long dirty_net_count; + unsigned long dirty_block_count; +} xc_shadow_control_stats_t; + +int xc_domain_create(int xc_handle, + unsigned int mem_kb, + const char *name, + int cpu, + u32 *pdomid); +int xc_domain_pause(int xc_handle, + u32 domid); +int xc_domain_unpause(int xc_handle, + u32 domid); +int xc_domain_destroy(int xc_handle, + u32 domid); +int xc_domain_pincpu(int xc_handle, + u32 domid, + int cpu); +int xc_domain_getinfo(int xc_handle, + u32 first_domid, + unsigned int max_doms, + xc_dominfo_t *info); + +int xc_shadow_control(int xc_handle, + u32 domid, + unsigned int sop, + unsigned long *dirty_bitmap, + unsigned long pages, + xc_shadow_control_stats_t *stats); + + +#define XCFLAGS_VERBOSE 1 +#define XCFLAGS_LIVE 2 +#define XCFLAGS_DEBUG 4 + +struct XcIOContext; +int xc_linux_save(int xc_handle, struct XcIOContext *ioctxt); +int xc_linux_restore(int xc_handle, struct XcIOContext *ioctxt); + +int xc_linux_build(int xc_handle, + u32 domid, + const char *image_name, + const char *ramdisk_name, + const char *cmdline, + unsigned int control_evtchn, + unsigned long flags); + +int xc_netbsd_build(int xc_handle, + u32 domid, + const char *image_name, + const char *cmdline, + unsigned int control_evtchn); + +int xc_bvtsched_global_set(int xc_handle, + unsigned long ctx_allow); + +int xc_bvtsched_domain_set(int xc_handle, + u32 domid, + unsigned long mcuadv, + unsigned long warp, + unsigned long warpl, + unsigned long warpu); + +int xc_bvtsched_global_get(int xc_handle, + unsigned long *ctx_allow); + +int xc_bvtsched_domain_get(int xc_handle, + u32 domid, + unsigned long *mcuadv, + unsigned long *warp, + unsigned long *warpl, + unsigned long *warpu); + +int xc_atropos_domain_set(int xc_handle, + u32 domid, + u64 period, u64 slice, u64 latency, + int xtratime); + +int xc_atropos_domain_get(int xc_handle, + u32 domid, + u64* period, u64 *slice, u64 *latency, + int *xtratime); + +int xc_rrobin_global_set(int xc_handle, u64 slice); + +int xc_rrobin_global_get(int xc_handle, u64 *slice); + +#define DOMID_SELF (0x7FFFFFFEU) + +typedef struct { +#define EVTCHNSTAT_closed 0 /* Chennel is not in use. */ +#define EVTCHNSTAT_unbound 1 /* Channel is not bound to a source. */ +#define EVTCHNSTAT_interdomain 2 /* Channel is connected to remote domain. */ +#define EVTCHNSTAT_pirq 3 /* Channel is bound to a phys IRQ line. */ +#define EVTCHNSTAT_virq 4 /* Channel is bound to a virtual IRQ line */ + int status; + union { + struct { + u32 dom; + int port; + } interdomain; + int pirq; + int virq; + } u; +} xc_evtchn_status_t; + +int xc_evtchn_bind_interdomain(int xc_handle, + u32 dom1, /* may be DOMID_SELF */ + u32 dom2, /* may be DOMID_SELF */ + int *port1, + int *port2); +int xc_evtchn_bind_virq(int xc_handle, + int virq, + int *port); +int xc_evtchn_close(int xc_handle, + u32 dom, /* may be DOMID_SELF */ + int port); +int xc_evtchn_send(int xc_handle, + int local_port); +int xc_evtchn_status(int xc_handle, + u32 dom, /* may be DOMID_SELF */ + int port, + xc_evtchn_status_t *status); + +int xc_physdev_pci_access_modify(int xc_handle, + u32 domid, + int bus, + int dev, + int func, + int enable); + +int xc_readconsolering(int xc_handle, + char *str, + unsigned int max_chars, + int clear); + +typedef struct { + int ht_per_core; + int cores; + unsigned long total_pages; + unsigned long free_pages; + unsigned long cpu_khz; +} xc_physinfo_t; + +int xc_physinfo(int xc_handle, + xc_physinfo_t *info); + +int xc_domain_setname(int xc_handle, + u32 domid, + char *name); + +int xc_domain_setinitialmem(int xc_handle, + u32 domid, + unsigned int initial_memkb); + +int xc_domain_setmaxmem(int xc_handle, + u32 domid, + unsigned int max_memkb); + + +#endif /* __XC_H__ */ diff --git a/tools/libxc/xc_atropos.c b/tools/libxc/xc_atropos.c new file mode 100644 index 0000000000..13d07ca440 --- /dev/null +++ b/tools/libxc/xc_atropos.c @@ -0,0 +1,51 @@ +/****************************************************************************** + * xc_atropos.c + * + * API for manipulating parameters of the Atropos scheduler. + * + * by Mark Williamson, Copyright (c) 2004 Intel Research Cambridge. + */ + +#include "xc_private.h" + +int xc_atropos_domain_set(int xc_handle, + u32 domid, u64 period, u64 slice, u64 latency, + int xtratime) +{ + dom0_op_t op; + struct atropos_adjdom *p = &op.u.adjustdom.u.atropos; + + op.cmd = DOM0_ADJUSTDOM; + op.u.adjustdom.domain = (domid_t)domid; + op.u.adjustdom.sched_id = SCHED_ATROPOS; + op.u.adjustdom.direction = SCHED_INFO_PUT; + + p->nat_period = period; + p->nat_slice = slice; + p->latency = latency; + p->xtratime = xtratime; + + return do_dom0_op(xc_handle, &op); +} + +int xc_atropos_domain_get(int xc_handle, u32 domid, u64 *period, + u64 *slice, u64 *latency, int *xtratime) +{ + dom0_op_t op; + int ret; + struct atropos_adjdom *p = &op.u.adjustdom.u.atropos; + + op.cmd = DOM0_ADJUSTDOM; + op.u.adjustdom.domain = (domid_t)domid; + op.u.adjustdom.sched_id = SCHED_ATROPOS; + op.u.adjustdom.direction = SCHED_INFO_GET; + + ret = do_dom0_op(xc_handle, &op); + + *period = p->nat_period; + *slice = p->nat_slice; + *latency = p->latency; + *xtratime = p->xtratime; + + return ret; +} diff --git a/tools/libxc/xc_bvtsched.c b/tools/libxc/xc_bvtsched.c new file mode 100644 index 0000000000..aeaddcfb04 --- /dev/null +++ b/tools/libxc/xc_bvtsched.c @@ -0,0 +1,88 @@ +/****************************************************************************** + * xc_bvtsched.c + * + * API for manipulating parameters of the Borrowed Virtual Time scheduler. + * + * Copyright (c) 2003, K A Fraser. + */ + +#include "xc_private.h" + +int xc_bvtsched_global_set(int xc_handle, + unsigned long ctx_allow) +{ + dom0_op_t op; + + op.cmd = DOM0_SCHEDCTL; + op.u.schedctl.sched_id = SCHED_BVT; + op.u.schedctl.direction = SCHED_INFO_PUT; + op.u.schedctl.u.bvt.ctx_allow = ctx_allow; + + return do_dom0_op(xc_handle, &op); +} + +int xc_bvtsched_global_get(int xc_handle, + unsigned long *ctx_allow) +{ + dom0_op_t op; + int ret; + + op.cmd = DOM0_SCHEDCTL; + op.u.schedctl.sched_id = SCHED_BVT; + op.u.schedctl.direction = SCHED_INFO_GET; + + ret = do_dom0_op(xc_handle, &op); + + *ctx_allow = op.u.schedctl.u.bvt.ctx_allow; + + return ret; +} + +int xc_bvtsched_domain_set(int xc_handle, + u32 domid, + unsigned long mcuadv, + unsigned long warp, + unsigned long warpl, + unsigned long warpu) +{ + dom0_op_t op; + struct bvt_adjdom *bvtadj = &op.u.adjustdom.u.bvt; + + op.cmd = DOM0_ADJUSTDOM; + op.u.adjustdom.domain = (domid_t)domid; + op.u.adjustdom.sched_id = SCHED_BVT; + op.u.adjustdom.direction = SCHED_INFO_PUT; + + bvtadj->mcu_adv = mcuadv; + bvtadj->warp = warp; + bvtadj->warpl = warpl; + bvtadj->warpu = warpu; + return do_dom0_op(xc_handle, &op); +} + + +int xc_bvtsched_domain_get(int xc_handle, + u32 domid, + unsigned long *mcuadv, + unsigned long *warp, + unsigned long *warpl, + unsigned long *warpu) +{ + + dom0_op_t op; + int ret; + struct bvt_adjdom *adjptr = &op.u.adjustdom.u.bvt; + + op.cmd = DOM0_ADJUSTDOM; + op.u.adjustdom.domain = (domid_t)domid; + op.u.adjustdom.sched_id = SCHED_BVT; + op.u.adjustdom.direction = SCHED_INFO_GET; + + ret = do_dom0_op(xc_handle, &op); + + *mcuadv = adjptr->mcu_adv; + *warp = adjptr->warp; + *warpl = adjptr->warpl; + *warpu = adjptr->warpu; + return ret; +} diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c new file mode 100644 index 0000000000..ab83d0ce7b --- /dev/null +++ b/tools/libxc/xc_domain.c @@ -0,0 +1,194 @@ +/****************************************************************************** + * xc_domain.c + * + * API for manipulating and obtaining information on domains. + * + * Copyright (c) 2003, K A Fraser. + */ + +#include "xc_private.h" + +int xc_domain_create(int xc_handle, + unsigned int mem_kb, + const char *name, + int cpu, + u32 *pdomid) +{ + int err; + dom0_op_t op; + + op.cmd = DOM0_CREATEDOMAIN; + op.u.createdomain.memory_kb = mem_kb; + strncpy(op.u.createdomain.name, name, MAX_DOMAIN_NAME); + op.u.createdomain.name[MAX_DOMAIN_NAME-1] = '\0'; + op.u.createdomain.cpu = cpu; + + if ( (err = do_dom0_op(xc_handle, &op)) == 0 ) + *pdomid = (u32)op.u.createdomain.domain; + + return err; +} + + +int xc_domain_pause(int xc_handle, + u32 domid) +{ + dom0_op_t op; + op.cmd = DOM0_PAUSEDOMAIN; + op.u.pausedomain.domain = (domid_t)domid; + return do_dom0_op(xc_handle, &op); +} + + +int xc_domain_unpause(int xc_handle, + u32 domid) +{ + dom0_op_t op; + op.cmd = DOM0_UNPAUSEDOMAIN; + op.u.unpausedomain.domain = (domid_t)domid; + return do_dom0_op(xc_handle, &op); +} + + +int xc_domain_destroy(int xc_handle, + u32 domid) +{ + dom0_op_t op; + op.cmd = DOM0_DESTROYDOMAIN; + op.u.destroydomain.domain = (domid_t)domid; + return do_dom0_op(xc_handle, &op); +} + +int xc_domain_pincpu(int xc_handle, + u32 domid, + int cpu) +{ + dom0_op_t op; + op.cmd = DOM0_PINCPUDOMAIN; + op.u.pincpudomain.domain = (domid_t)domid; + op.u.pincpudomain.cpu = cpu; + return do_dom0_op(xc_handle, &op); +} + + +int xc_domain_getinfo(int xc_handle, + u32 first_domid, + unsigned int max_doms, + xc_dominfo_t *info) +{ + unsigned int nr_doms; + u32 next_domid = first_domid; + dom0_op_t op; + + for ( nr_doms = 0; nr_doms < max_doms; nr_doms++ ) + { + op.cmd = DOM0_GETDOMAININFO; + op.u.getdomaininfo.domain = (domid_t)next_domid; + op.u.getdomaininfo.ctxt = NULL; /* no exec context info, thanks. */ + if ( do_dom0_op(xc_handle, &op) < 0 ) + break; + info->domid = (u32)op.u.getdomaininfo.domain; + + info->cpu = + (op.u.getdomaininfo.flags>>DOMFLAGS_CPUSHIFT) & DOMFLAGS_CPUMASK; + + info->dying = !!(op.u.getdomaininfo.flags & DOMFLAGS_DYING); + info->crashed = !!(op.u.getdomaininfo.flags & DOMFLAGS_CRASHED); + info->shutdown = !!(op.u.getdomaininfo.flags & DOMFLAGS_SHUTDOWN); + info->paused = !!(op.u.getdomaininfo.flags & DOMFLAGS_PAUSED); + info->blocked = !!(op.u.getdomaininfo.flags & DOMFLAGS_BLOCKED); + info->running = !!(op.u.getdomaininfo.flags & DOMFLAGS_RUNNING); + + info->shutdown_reason = + (op.u.getdomaininfo.flags>>DOMFLAGS_SHUTDOWNSHIFT) & + DOMFLAGS_SHUTDOWNMASK; + + info->nr_pages = op.u.getdomaininfo.tot_pages; + info->max_memkb = op.u.getdomaininfo.max_pages<<(PAGE_SHIFT-10); + info->shared_info_frame = op.u.getdomaininfo.shared_info_frame; + info->cpu_time = op.u.getdomaininfo.cpu_time; + strncpy(info->name, op.u.getdomaininfo.name, XC_DOMINFO_MAXNAME); + info->name[XC_DOMINFO_MAXNAME-1] = '\0'; + + next_domid = (u32)op.u.getdomaininfo.domain + 1; + info++; + } + + return nr_doms; +} + +int xc_domain_getfullinfo(int xc_handle, + u32 domid, + dom0_op_t *op, + full_execution_context_t *ctxt ) +{ + int rc; + op->cmd = DOM0_GETDOMAININFO; + op->u.getdomaininfo.domain = (domid_t)domid; + op->u.getdomaininfo.ctxt = ctxt; + + rc = do_dom0_op(xc_handle, op); + if ( ((u32)op->u.getdomaininfo.domain != domid) && rc > 0 ) + return -ESRCH; + else + return rc; +} + + +int xc_shadow_control(int xc_handle, + u32 domid, + unsigned int sop, + unsigned long *dirty_bitmap, + unsigned long pages, + xc_shadow_control_stats_t *stats ) +{ + int rc; + dom0_op_t op; + op.cmd = DOM0_SHADOW_CONTROL; + op.u.shadow_control.domain = (domid_t)domid; + op.u.shadow_control.op = sop; + op.u.shadow_control.dirty_bitmap = dirty_bitmap; + op.u.shadow_control.pages = pages; + + rc = do_dom0_op(xc_handle, &op); + + if ( stats ) + memcpy(stats, &op.u.shadow_control.stats, + sizeof(xc_shadow_control_stats_t)); + + return (rc == 0) ? op.u.shadow_control.pages : rc; +} + +int xc_domain_setname(int xc_handle, + u32 domid, + char *name) +{ + dom0_op_t op; + op.cmd = DOM0_SETDOMAINNAME; + op.u.setdomainname.domain = (domid_t)domid; + strncpy(op.u.setdomainname.name, name, MAX_DOMAIN_NAME); + return do_dom0_op(xc_handle, &op); +} + +int xc_domain_setinitialmem(int xc_handle, + u32 domid, + unsigned int initial_memkb) +{ + dom0_op_t op; + op.cmd = DOM0_SETDOMAININITIALMEM; + op.u.setdomaininitialmem.domain = (domid_t)domid; + op.u.setdomaininitialmem.initial_memkb = initial_memkb; + return do_dom0_op(xc_handle, &op); +} + +int xc_domain_setmaxmem(int xc_handle, + u32 domid, + unsigned int max_memkb) +{ + dom0_op_t op; + op.cmd = DOM0_SETDOMAINMAXMEM; + op.u.setdomainmaxmem.domain = (domid_t)domid; + op.u.setdomainmaxmem.max_memkb = max_memkb; + return do_dom0_op(xc_handle, &op); +} + diff --git a/tools/libxc/xc_elf.h b/tools/libxc/xc_elf.h new file mode 100644 index 0000000000..e0d0c26131 --- /dev/null +++ b/tools/libxc/xc_elf.h @@ -0,0 +1,523 @@ +/* + * Copyright (c) 1995, 1996 Erik Theisen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +typedef u_int8_t Elf_Byte; + +typedef u_int32_t Elf32_Addr; /* Unsigned program address */ +typedef u_int32_t Elf32_Off; /* Unsigned file offset */ +typedef int32_t Elf32_Sword; /* Signed large integer */ +typedef u_int32_t Elf32_Word; /* Unsigned large integer */ +typedef u_int16_t Elf32_Half; /* Unsigned medium integer */ + +typedef u_int64_t Elf64_Addr; +typedef u_int64_t Elf64_Off; +typedef int32_t Elf64_Shalf; + +typedef int32_t Elf64_Sword; +typedef u_int32_t Elf64_Word; + +typedef int64_t Elf64_Sxword; +typedef u_int64_t Elf64_Xword; + +typedef u_int32_t Elf64_Half; +typedef u_int16_t Elf64_Quarter; + +/* + * e_ident[] identification indexes + * See http://www.caldera.com/developers/gabi/2000-07-17/ch4.eheader.html + */ +#define EI_MAG0 0 /* file ID */ +#define EI_MAG1 1 /* file ID */ +#define EI_MAG2 2 /* file ID */ +#define EI_MAG3 3 /* file ID */ +#define EI_CLASS 4 /* file class */ +#define EI_DATA 5 /* data encoding */ +#define EI_VERSION 6 /* ELF header version */ +#define EI_OSABI 7 /* OS/ABI ID */ +#define EI_ABIVERSION 8 /* ABI version */ +#define EI_PAD 9 /* start of pad bytes */ +#define EI_NIDENT 16 /* Size of e_ident[] */ + +/* e_ident[] magic number */ +#define ELFMAG0 0x7f /* e_ident[EI_MAG0] */ +#define ELFMAG1 'E' /* e_ident[EI_MAG1] */ +#define ELFMAG2 'L' /* e_ident[EI_MAG2] */ +#define ELFMAG3 'F' /* e_ident[EI_MAG3] */ +#define ELFMAG "\177ELF" /* magic */ +#define SELFMAG 4 /* size of magic */ + +/* e_ident[] file class */ +#define ELFCLASSNONE 0 /* invalid */ +#define ELFCLASS32 1 /* 32-bit objs */ +#define ELFCLASS64 2 /* 64-bit objs */ +#define ELFCLASSNUM 3 /* number of classes */ + +/* e_ident[] data encoding */ +#define ELFDATANONE 0 /* invalid */ +#define ELFDATA2LSB 1 /* Little-Endian */ +#define ELFDATA2MSB 2 /* Big-Endian */ +#define ELFDATANUM 3 /* number of data encode defines */ + +/* e_ident[] Operating System/ABI */ +#define ELFOSABI_SYSV 0 /* UNIX System V ABI */ +#define ELFOSABI_HPUX 1 /* HP-UX operating system */ +#define ELFOSABI_NETBSD 2 /* NetBSD */ +#define ELFOSABI_LINUX 3 /* GNU/Linux */ +#define ELFOSABI_HURD 4 /* GNU/Hurd */ +#define ELFOSABI_86OPEN 5 /* 86Open common IA32 ABI */ +#define ELFOSABI_SOLARIS 6 /* Solaris */ +#define ELFOSABI_MONTEREY 7 /* Monterey */ +#define ELFOSABI_IRIX 8 /* IRIX */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD */ +#define ELFOSABI_TRU64 10 /* TRU64 UNIX */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD */ +#define ELFOSABI_ARM 97 /* ARM */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ + +/* e_ident */ +#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \ + (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \ + (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \ + (ehdr).e_ident[EI_MAG3] == ELFMAG3) + +/* ELF Header */ +typedef struct elfhdr { + unsigned char e_ident[EI_NIDENT]; /* ELF Identification */ + Elf32_Half e_type; /* object file type */ + Elf32_Half e_machine; /* machine */ + Elf32_Word e_version; /* object file version */ + Elf32_Addr e_entry; /* virtual entry point */ + Elf32_Off e_phoff; /* program header table offset */ + Elf32_Off e_shoff; /* section header table offset */ + Elf32_Word e_flags; /* processor-specific flags */ + Elf32_Half e_ehsize; /* ELF header size */ + Elf32_Half e_phentsize; /* program header entry size */ + Elf32_Half e_phnum; /* number of program header entries */ + Elf32_Half e_shentsize; /* section header entry size */ + Elf32_Half e_shnum; /* number of section header entries */ + Elf32_Half e_shstrndx; /* section header table's "section + header string table" entry offset */ +} Elf32_Ehdr; + +typedef struct { + unsigned char e_ident[EI_NIDENT]; /* Id bytes */ + Elf64_Quarter e_type; /* file type */ + Elf64_Quarter e_machine; /* machine type */ + Elf64_Half e_version; /* version number */ + Elf64_Addr e_entry; /* entry point */ + Elf64_Off e_phoff; /* Program hdr offset */ + Elf64_Off e_shoff; /* Section hdr offset */ + Elf64_Half e_flags; /* Processor flags */ + Elf64_Quarter e_ehsize; /* sizeof ehdr */ + Elf64_Quarter e_phentsize; /* Program header entry size */ + Elf64_Quarter e_phnum; /* Number of program headers */ + Elf64_Quarter e_shentsize; /* Section header entry size */ + Elf64_Quarter e_shnum; /* Number of section headers */ + Elf64_Quarter e_shstrndx; /* String table index */ +} Elf64_Ehdr; + +/* e_type */ +#define ET_NONE 0 /* No file type */ +#define ET_REL 1 /* relocatable file */ +#define ET_EXEC 2 /* executable file */ +#define ET_DYN 3 /* shared object file */ +#define ET_CORE 4 /* core file */ +#define ET_NUM 5 /* number of types */ +#define ET_LOPROC 0xff00 /* reserved range for processor */ +#define ET_HIPROC 0xffff /* specific e_type */ + +/* e_machine */ +#define EM_NONE 0 /* No Machine */ +#define EM_M32 1 /* AT&T WE 32100 */ +#define EM_SPARC 2 /* SPARC */ +#define EM_386 3 /* Intel 80386 */ +#define EM_68K 4 /* Motorola 68000 */ +#define EM_88K 5 /* Motorola 88000 */ +#define EM_486 6 /* Intel 80486 - unused? */ +#define EM_860 7 /* Intel 80860 */ +#define EM_MIPS 8 /* MIPS R3000 Big-Endian only */ +/* + * Don't know if EM_MIPS_RS4_BE, + * EM_SPARC64, EM_PARISC, + * or EM_PPC are ABI compliant + */ +#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */ +#define EM_SPARC64 11 /* SPARC v9 64-bit unoffical */ +#define EM_PARISC 15 /* HPPA */ +#define EM_SPARC32PLUS 18 /* Enhanced instruction set SPARC */ +#define EM_PPC 20 /* PowerPC */ +#define EM_ARM 40 /* Advanced RISC Machines ARM */ +#define EM_ALPHA 41 /* DEC ALPHA */ +#define EM_SPARCV9 43 /* SPARC version 9 */ +#define EM_ALPHA_EXP 0x9026 /* DEC ALPHA */ +#define EM_X86_64 62 /* AMD x86-64 architecture */ +#define EM_VAX 75 /* DEC VAX */ +#define EM_NUM 15 /* number of machine types */ + +/* Version */ +#define EV_NONE 0 /* Invalid */ +#define EV_CURRENT 1 /* Current */ +#define EV_NUM 2 /* number of versions */ + +/* Section Header */ +typedef struct { + Elf32_Word sh_name; /* name - index into section header + string table section */ + Elf32_Word sh_type; /* type */ + Elf32_Word sh_flags; /* flags */ + Elf32_Addr sh_addr; /* address */ + Elf32_Off sh_offset; /* file offset */ + Elf32_Word sh_size; /* section size */ + Elf32_Word sh_link; /* section header table index link */ + Elf32_Word sh_info; /* extra information */ + Elf32_Word sh_addralign; /* address alignment */ + Elf32_Word sh_entsize; /* section entry size */ +} Elf32_Shdr; + +typedef struct { + Elf64_Half sh_name; /* section name */ + Elf64_Half sh_type; /* section type */ + Elf64_Xword sh_flags; /* section flags */ + Elf64_Addr sh_addr; /* virtual address */ + Elf64_Off sh_offset; /* file offset */ + Elf64_Xword sh_size; /* section size */ + Elf64_Half sh_link; /* link to another */ + Elf64_Half sh_info; /* misc info */ + Elf64_Xword sh_addralign; /* memory alignment */ + Elf64_Xword sh_entsize; /* table entry size */ +} Elf64_Shdr; + +/* Special Section Indexes */ +#define SHN_UNDEF 0 /* undefined */ +#define SHN_LORESERVE 0xff00 /* lower bounds of reserved indexes */ +#define SHN_LOPROC 0xff00 /* reserved range for processor */ +#define SHN_HIPROC 0xff1f /* specific section indexes */ +#define SHN_ABS 0xfff1 /* absolute value */ +#define SHN_COMMON 0xfff2 /* common symbol */ +#define SHN_HIRESERVE 0xffff /* upper bounds of reserved indexes */ + +/* sh_type */ +#define SHT_NULL 0 /* inactive */ +#define SHT_PROGBITS 1 /* program defined information */ +#define SHT_SYMTAB 2 /* symbol table section */ +#define SHT_STRTAB 3 /* string table section */ +#define SHT_RELA 4 /* relocation section with addends*/ +#define SHT_HASH 5 /* symbol hash table section */ +#define SHT_DYNAMIC 6 /* dynamic section */ +#define SHT_NOTE 7 /* note section */ +#define SHT_NOBITS 8 /* no space section */ +#define SHT_REL 9 /* relation section without addends */ +#define SHT_SHLIB 10 /* reserved - purpose unknown */ +#define SHT_DYNSYM 11 /* dynamic symbol table section */ +#define SHT_NUM 12 /* number of section types */ +#define SHT_LOPROC 0x70000000 /* reserved range for processor */ +#define SHT_HIPROC 0x7fffffff /* specific section header types */ +#define SHT_LOUSER 0x80000000 /* reserved range for application */ +#define SHT_HIUSER 0xffffffff /* specific indexes */ + +/* Section names */ +#define ELF_BSS ".bss" /* uninitialized data */ +#define ELF_DATA ".data" /* initialized data */ +#define ELF_DEBUG ".debug" /* debug */ +#define ELF_DYNAMIC ".dynamic" /* dynamic linking information */ +#define ELF_DYNSTR ".dynstr" /* dynamic string table */ +#define ELF_DYNSYM ".dynsym" /* dynamic symbol table */ +#define ELF_FINI ".fini" /* termination code */ +#define ELF_GOT ".got" /* global offset table */ +#define ELF_HASH ".hash" /* symbol hash table */ +#define ELF_INIT ".init" /* initialization code */ +#define ELF_REL_DATA ".rel.data" /* relocation data */ +#define ELF_REL_FINI ".rel.fini" /* relocation termination code */ +#define ELF_REL_INIT ".rel.init" /* relocation initialization code */ +#define ELF_REL_DYN ".rel.dyn" /* relocaltion dynamic link info */ +#define ELF_REL_RODATA ".rel.rodata" /* relocation read-only data */ +#define ELF_REL_TEXT ".rel.text" /* relocation code */ +#define ELF_RODATA ".rodata" /* read-only data */ +#define ELF_SHSTRTAB ".shstrtab" /* section header string table */ +#define ELF_STRTAB ".strtab" /* string table */ +#define ELF_SYMTAB ".symtab" /* symbol table */ +#define ELF_TEXT ".text" /* code */ + + +/* Section Attribute Flags - sh_flags */ +#define SHF_WRITE 0x1 /* Writable */ +#define SHF_ALLOC 0x2 /* occupies memory */ +#define SHF_EXECINSTR 0x4 /* executable */ +#define SHF_MASKPROC 0xf0000000 /* reserved bits for processor */ + /* specific section attributes */ + +/* Symbol Table Entry */ +typedef struct elf32_sym { + Elf32_Word st_name; /* name - index into string table */ + Elf32_Addr st_value; /* symbol value */ + Elf32_Word st_size; /* symbol size */ + unsigned char st_info; /* type and binding */ + unsigned char st_other; /* 0 - no defined meaning */ + Elf32_Half st_shndx; /* section header index */ +} Elf32_Sym; + +typedef struct { + Elf64_Half st_name; /* Symbol name index in str table */ + Elf_Byte st_info; /* type / binding attrs */ + Elf_Byte st_other; /* unused */ + Elf64_Quarter st_shndx; /* section index of symbol */ + Elf64_Xword st_value; /* value of symbol */ + Elf64_Xword st_size; /* size of symbol */ +} Elf64_Sym; + +/* Symbol table index */ +#define STN_UNDEF 0 /* undefined */ + +/* Extract symbol info - st_info */ +#define ELF32_ST_BIND(x) ((x) >> 4) +#define ELF32_ST_TYPE(x) (((unsigned int) x) & 0xf) +#define ELF32_ST_INFO(b,t) (((b) << 4) + ((t) & 0xf)) + +#define ELF64_ST_BIND(x) ((x) >> 4) +#define ELF64_ST_TYPE(x) (((unsigned int) x) & 0xf) +#define ELF64_ST_INFO(b,t) (((b) << 4) + ((t) & 0xf)) + +/* Symbol Binding - ELF32_ST_BIND - st_info */ +#define STB_LOCAL 0 /* Local symbol */ +#define STB_GLOBAL 1 /* Global symbol */ +#define STB_WEAK 2 /* like global - lower precedence */ +#define STB_NUM 3 /* number of symbol bindings */ +#define STB_LOPROC 13 /* reserved range for processor */ +#define STB_HIPROC 15 /* specific symbol bindings */ + +/* Symbol type - ELF32_ST_TYPE - st_info */ +#define STT_NOTYPE 0 /* not specified */ +#define STT_OBJECT 1 /* data object */ +#define STT_FUNC 2 /* function */ +#define STT_SECTION 3 /* section */ +#define STT_FILE 4 /* file */ +#define STT_NUM 5 /* number of symbol types */ +#define STT_LOPROC 13 /* reserved range for processor */ +#define STT_HIPROC 15 /* specific symbol types */ + +/* Relocation entry with implicit addend */ +typedef struct { + Elf32_Addr r_offset; /* offset of relocation */ + Elf32_Word r_info; /* symbol table index and type */ +} Elf32_Rel; + +/* Relocation entry with explicit addend */ +typedef struct { + Elf32_Addr r_offset; /* offset of relocation */ + Elf32_Word r_info; /* symbol table index and type */ + Elf32_Sword r_addend; +} Elf32_Rela; + +/* Extract relocation info - r_info */ +#define ELF32_R_SYM(i) ((i) >> 8) +#define ELF32_R_TYPE(i) ((unsigned char) (i)) +#define ELF32_R_INFO(s,t) (((s) << 8) + (unsigned char)(t)) + +typedef struct { + Elf64_Xword r_offset; /* where to do it */ + Elf64_Xword r_info; /* index & type of relocation */ +} Elf64_Rel; + +typedef struct { + Elf64_Xword r_offset; /* where to do it */ + Elf64_Xword r_info; /* index & type of relocation */ + Elf64_Sxword r_addend; /* adjustment value */ +} Elf64_Rela; + +#define ELF64_R_SYM(info) ((info) >> 32) +#define ELF64_R_TYPE(info) ((info) & 0xFFFFFFFF) +#define ELF64_R_INFO(s,t) (((s) << 32) + (u_int32_t)(t)) + +/* Program Header */ +typedef struct { + Elf32_Word p_type; /* segment type */ + Elf32_Off p_offset; /* segment offset */ + Elf32_Addr p_vaddr; /* virtual address of segment */ + Elf32_Addr p_paddr; /* physical address - ignored? */ + Elf32_Word p_filesz; /* number of bytes in file for seg. */ + Elf32_Word p_memsz; /* number of bytes in mem. for seg. */ + Elf32_Word p_flags; /* flags */ + Elf32_Word p_align; /* memory alignment */ +} Elf32_Phdr; + +typedef struct { + Elf64_Half p_type; /* entry type */ + Elf64_Half p_flags; /* flags */ + Elf64_Off p_offset; /* offset */ + Elf64_Addr p_vaddr; /* virtual address */ + Elf64_Addr p_paddr; /* physical address */ + Elf64_Xword p_filesz; /* file size */ + Elf64_Xword p_memsz; /* memory size */ + Elf64_Xword p_align; /* memory & file alignment */ +} Elf64_Phdr; + +/* Segment types - p_type */ +#define PT_NULL 0 /* unused */ +#define PT_LOAD 1 /* loadable segment */ +#define PT_DYNAMIC 2 /* dynamic linking section */ +#define PT_INTERP 3 /* the RTLD */ +#define PT_NOTE 4 /* auxiliary information */ +#define PT_SHLIB 5 /* reserved - purpose undefined */ +#define PT_PHDR 6 /* program header */ +#define PT_NUM 7 /* Number of segment types */ +#define PT_LOPROC 0x70000000 /* reserved range for processor */ +#define PT_HIPROC 0x7fffffff /* specific segment types */ + +/* Segment flags - p_flags */ +#define PF_X 0x1 /* Executable */ +#define PF_W 0x2 /* Writable */ +#define PF_R 0x4 /* Readable */ +#define PF_MASKPROC 0xf0000000 /* reserved bits for processor */ + /* specific segment flags */ + +/* Dynamic structure */ +typedef struct { + Elf32_Sword d_tag; /* controls meaning of d_val */ + union { + Elf32_Word d_val; /* Multiple meanings - see d_tag */ + Elf32_Addr d_ptr; /* program virtual address */ + } d_un; +} Elf32_Dyn; + +typedef struct { + Elf64_Xword d_tag; /* controls meaning of d_val */ + union { + Elf64_Addr d_ptr; + Elf64_Xword d_val; + } d_un; +} Elf64_Dyn; + +/* Dynamic Array Tags - d_tag */ +#define DT_NULL 0 /* marks end of _DYNAMIC array */ +#define DT_NEEDED 1 /* string table offset of needed lib */ +#define DT_PLTRELSZ 2 /* size of relocation entries in PLT */ +#define DT_PLTGOT 3 /* address PLT/GOT */ +#define DT_HASH 4 /* address of symbol hash table */ +#define DT_STRTAB 5 /* address of string table */ +#define DT_SYMTAB 6 /* address of symbol table */ +#define DT_RELA 7 /* address of relocation table */ +#define DT_RELASZ 8 /* size of relocation table */ +#define DT_RELAENT 9 /* size of relocation entry */ +#define DT_STRSZ 10 /* size of string table */ +#define DT_SYMENT 11 /* size of symbol table entry */ +#define DT_INIT 12 /* address of initialization func. */ +#define DT_FINI 13 /* address of termination function */ +#define DT_SONAME 14 /* string table offset of shared obj */ +#define DT_RPATH 15 /* string table offset of library + search path */ +#define DT_SYMBOLIC 16 /* start sym search in shared obj. */ +#define DT_REL 17 /* address of rel. tbl. w addends */ +#define DT_RELSZ 18 /* size of DT_REL relocation table */ +#define DT_RELENT 19 /* size of DT_REL relocation entry */ +#define DT_PLTREL 20 /* PLT referenced relocation entry */ +#define DT_DEBUG 21 /* bugger */ +#define DT_TEXTREL 22 /* Allow rel. mod. to unwritable seg */ +#define DT_JMPREL 23 /* add. of PLT's relocation entries */ +#define DT_BIND_NOW 24 /* Bind now regardless of env setting */ +#define DT_NUM 25 /* Number used. */ +#define DT_LOPROC 0x70000000 /* reserved range for processor */ +#define DT_HIPROC 0x7fffffff /* specific dynamic array tags */ + +/* Standard ELF hashing function */ +unsigned int elf_hash(const unsigned char *name); + +/* + * Note Definitions + */ +typedef struct { + Elf32_Word namesz; + Elf32_Word descsz; + Elf32_Word type; +} Elf32_Note; + +typedef struct { + Elf64_Half namesz; + Elf64_Half descsz; + Elf64_Half type; +} Elf64_Note; + + +#if defined(ELFSIZE) +#define CONCAT(x,y) __CONCAT(x,y) +#define ELFNAME(x) CONCAT(elf,CONCAT(ELFSIZE,CONCAT(_,x))) +#define ELFNAME2(x,y) CONCAT(x,CONCAT(_elf,CONCAT(ELFSIZE,CONCAT(_,y)))) +#define ELFNAMEEND(x) CONCAT(x,CONCAT(_elf,ELFSIZE)) +#define ELFDEFNNAME(x) CONCAT(ELF,CONCAT(ELFSIZE,CONCAT(_,x))) +#endif + +#if defined(ELFSIZE) && (ELFSIZE == 32) +#define Elf_Ehdr Elf32_Ehdr +#define Elf_Phdr Elf32_Phdr +#define Elf_Shdr Elf32_Shdr +#define Elf_Sym Elf32_Sym +#define Elf_Rel Elf32_Rel +#define Elf_RelA Elf32_Rela +#define Elf_Dyn Elf32_Dyn +#define Elf_Word Elf32_Word +#define Elf_Sword Elf32_Sword +#define Elf_Addr Elf32_Addr +#define Elf_Off Elf32_Off +#define Elf_Nhdr Elf32_Nhdr +#define Elf_Note Elf32_Note + +#define ELF_R_SYM ELF32_R_SYM +#define ELF_R_TYPE ELF32_R_TYPE +#define ELF_R_INFO ELF32_R_INFO +#define ELFCLASS ELFCLASS32 + +#define ELF_ST_BIND ELF32_ST_BIND +#define ELF_ST_TYPE ELF32_ST_TYPE +#define ELF_ST_INFO ELF32_ST_INFO + +#define AuxInfo Aux32Info +#elif defined(ELFSIZE) && (ELFSIZE == 64) +#define Elf_Ehdr Elf64_Ehdr +#define Elf_Phdr Elf64_Phdr +#define Elf_Shdr Elf64_Shdr +#define Elf_Sym Elf64_Sym +#define Elf_Rel Elf64_Rel +#define Elf_RelA Elf64_Rela +#define Elf_Dyn Elf64_Dyn +#define Elf_Word Elf64_Word +#define Elf_Sword Elf64_Sword +#define Elf_Addr Elf64_Addr +#define Elf_Off Elf64_Off +#define Elf_Nhdr Elf64_Nhdr +#define Elf_Note Elf64_Note + +#define ELF_R_SYM ELF64_R_SYM +#define ELF_R_TYPE ELF64_R_TYPE +#define ELF_R_INFO ELF64_R_INFO +#define ELFCLASS ELFCLASS64 + +#define ELF_ST_BIND ELF64_ST_BIND +#define ELF_ST_TYPE ELF64_ST_TYPE +#define ELF_ST_INFO ELF64_ST_INFO + +#define AuxInfo Aux64Info +#endif + diff --git a/tools/libxc/xc_evtchn.c b/tools/libxc/xc_evtchn.c new file mode 100644 index 0000000000..624f5b1c15 --- /dev/null +++ b/tools/libxc/xc_evtchn.c @@ -0,0 +1,131 @@ +/****************************************************************************** + * xc_evtchn.c + * + * API for manipulating and accessing inter-domain event channels. + * + * Copyright (c) 2004, K A Fraser. + */ + +#include "xc_private.h" + + +static int do_evtchn_op(int xc_handle, evtchn_op_t *op) +{ + int ret = -1; + privcmd_hypercall_t hypercall; + + hypercall.op = __HYPERVISOR_event_channel_op; + hypercall.arg[0] = (unsigned long)op; + + if ( mlock(op, sizeof(*op)) != 0 ) + { + PERROR("Could not lock memory for Xen hypercall"); + goto out1; + } + + if ( (ret = do_xen_hypercall(xc_handle, &hypercall)) < 0 ) + goto out2; + + out2: (void)munlock(op, sizeof(*op)); + out1: return ret; +} + + +int xc_evtchn_bind_interdomain(int xc_handle, + u32 dom1, + u32 dom2, + int *port1, + int *port2) +{ + evtchn_op_t op; + int rc; + + op.cmd = EVTCHNOP_bind_interdomain; + op.u.bind_interdomain.dom1 = (domid_t)dom1; + op.u.bind_interdomain.dom2 = (domid_t)dom2; + + if ( (rc = do_evtchn_op(xc_handle, &op)) == 0 ) + { + if ( port1 != NULL ) + *port1 = op.u.bind_interdomain.port1; + if ( port2 != NULL ) + *port2 = op.u.bind_interdomain.port2; + } + + return rc; +} + + +int xc_evtchn_bind_virq(int xc_handle, + int virq, + int *port) +{ + evtchn_op_t op; + int rc; + + op.cmd = EVTCHNOP_bind_virq; + op.u.bind_virq.virq = (u32)virq; + + if ( (rc = do_evtchn_op(xc_handle, &op)) == 0 ) + { + if ( port != NULL ) + *port = op.u.bind_virq.port; + } + + return rc; +} + + +int xc_evtchn_close(int xc_handle, + u32 dom, + int port) +{ + evtchn_op_t op; + op.cmd = EVTCHNOP_close; + op.u.close.dom = (domid_t)dom; + op.u.close.port = port; + return do_evtchn_op(xc_handle, &op); +} + + +int xc_evtchn_send(int xc_handle, + int local_port) +{ + evtchn_op_t op; + op.cmd = EVTCHNOP_send; + op.u.send.local_port = local_port; + return do_evtchn_op(xc_handle, &op); +} + + +int xc_evtchn_status(int xc_handle, + u32 dom, + int port, + xc_evtchn_status_t *status) +{ + evtchn_op_t op; + int rc; + + op.cmd = EVTCHNOP_status; + op.u.status.dom = (domid_t)dom; + op.u.status.port = port; + + if ( (rc = do_evtchn_op(xc_handle, &op)) == 0 ) + { + switch ( status->status = op.u.status.status ) + { + case EVTCHNSTAT_interdomain: + status->u.interdomain.dom = (u32)op.u.status.u.interdomain.dom; + status->u.interdomain.port = op.u.status.u.interdomain.port; + break; + case EVTCHNSTAT_pirq: + status->u.pirq = op.u.status.u.pirq; + break; + case EVTCHNSTAT_virq: + status->u.virq = op.u.status.u.virq; + break; + } + } + + return rc; +} diff --git a/tools/libxc/xc_io.c b/tools/libxc/xc_io.c new file mode 100644 index 0000000000..b7ce6342ab --- /dev/null +++ b/tools/libxc/xc_io.c @@ -0,0 +1,31 @@ +#include "xc_io.h" + +void xcio_error(XcIOContext *ctxt, const char *msg, ...){ + va_list args; + + va_start(args, msg); + vfprintf(stdout, msg, args); fprintf(stdout, "\n"); + IOStream_vprint(ctxt->info, msg, args); + IOStream_print(ctxt->info, "\n"); + va_end(args); +} + +void xcio_info(XcIOContext *ctxt, const char *msg, ...){ + va_list args; + + if(0 && !(ctxt->flags & XCFLAGS_VERBOSE)) return; + va_start(args, msg); + vfprintf(stdout, msg, args); fprintf(stdout, "\n"); + IOStream_vprint(ctxt->info, msg, args); + va_end(args); +} + +void xcio_debug(XcIOContext *ctxt, const char *msg, ...){ + va_list args; + + if(0 && !(ctxt->flags & XCFLAGS_DEBUG)) return; + va_start(args, msg); + vfprintf(stdout, msg, args); fprintf(stdout, "\n"); + IOStream_vprint(ctxt->info, msg, args); + va_end(args); +} diff --git a/tools/libxc/xc_io.h b/tools/libxc/xc_io.h new file mode 100644 index 0000000000..37febb52f1 --- /dev/null +++ b/tools/libxc/xc_io.h @@ -0,0 +1,44 @@ +#ifndef __XC_XC_IO_H__ +#define __XC_XC_IO_H__ + +#include "xc_private.h" +#include "iostream.h" + +typedef struct XcIOContext { + u32 domain; + unsigned flags; + IOStream *io; + IOStream *info; + IOStream *err; + char *vmconfig; + int vmconfig_n; +} XcIOContext; + +static inline int xcio_read(XcIOContext *ctxt, void *buf, int n){ + int rc; + + rc = IOStream_read(ctxt->io, buf, n); + return (rc == n ? 0 : rc); +} + +static inline int xcio_write(XcIOContext *ctxt, void *buf, int n){ + int rc; + + rc = IOStream_write(ctxt->io, buf, n); + return (rc == n ? 0 : rc); +} + +static inline int xcio_flush(XcIOContext *ctxt){ + return IOStream_flush(ctxt->io); +} + +extern void xcio_error(XcIOContext *ctxt, const char *msg, ...); +extern void xcio_info(XcIOContext *ctxt, const char *msg, ...); + +#define xcio_perror(_ctxt, _msg...) \ +xcio_error(_ctxt, "(errno %d %s)" _msg, errno, strerror(errno), ## _msg) + +#endif /* ! __XC_XC_IO_H__ */ + + + diff --git a/tools/libxc/xc_linux_build.c b/tools/libxc/xc_linux_build.c new file mode 100644 index 0000000000..ceace01b00 --- /dev/null +++ b/tools/libxc/xc_linux_build.c @@ -0,0 +1,675 @@ +/****************************************************************************** + * xc_linux_build.c + */ + +#include "xc_private.h" +#define ELFSIZE 32 +#include "xc_elf.h" +#include + +#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED) +#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER) + +#define round_pgup(_p) (((_p)+(PAGE_SIZE-1))&PAGE_MASK) +#define round_pgdown(_p) ((_p)&PAGE_MASK) + +static int readelfimage_base_and_size(char *elfbase, + unsigned long elfsize, + unsigned long *pkernstart, + unsigned long *pkernend, + unsigned long *pkernentry); +static int loadelfimage(char *elfbase, int pmh, unsigned long *parray, + unsigned long vstart); + +static long get_tot_pages(int xc_handle, u32 domid) +{ + dom0_op_t op; + op.cmd = DOM0_GETDOMAININFO; + op.u.getdomaininfo.domain = (domid_t)domid; + op.u.getdomaininfo.ctxt = NULL; + return (do_dom0_op(xc_handle, &op) < 0) ? + -1 : op.u.getdomaininfo.tot_pages; +} + +static int get_pfn_list(int xc_handle, + u32 domid, + unsigned long *pfn_buf, + unsigned long max_pfns) +{ + dom0_op_t op; + int ret; + op.cmd = DOM0_GETMEMLIST; + op.u.getmemlist.domain = (domid_t)domid; + op.u.getmemlist.max_pfns = max_pfns; + op.u.getmemlist.buffer = pfn_buf; + + if ( mlock(pfn_buf, max_pfns * sizeof(unsigned long)) != 0 ) + return -1; + + ret = do_dom0_op(xc_handle, &op); + + (void)munlock(pfn_buf, max_pfns * sizeof(unsigned long)); + + return (ret < 0) ? -1 : op.u.getmemlist.num_pfns; +} + +static int copy_to_domain_page(int pm_handle, + unsigned long dst_pfn, + void *src_page) +{ + void *vaddr = map_pfn_writeable(pm_handle, dst_pfn); + if ( vaddr == NULL ) + return -1; + memcpy(vaddr, src_page, PAGE_SIZE); + unmap_pfn(pm_handle, vaddr); + return 0; +} + +static int setup_guestos(int xc_handle, + u32 dom, + char *image, unsigned long image_size, + gzFile initrd_gfd, unsigned long initrd_len, + unsigned long nr_pages, + unsigned long *pvsi, unsigned long *pvke, + full_execution_context_t *ctxt, + const char *cmdline, + unsigned long shared_info_frame, + unsigned int control_evtchn, + unsigned long flags) +{ + l1_pgentry_t *vl1tab=NULL, *vl1e=NULL; + l2_pgentry_t *vl2tab=NULL, *vl2e=NULL; + unsigned long *page_array = NULL; + unsigned long l2tab; + unsigned long l1tab; + unsigned long count, i; + extended_start_info_t *start_info; + shared_info_t *shared_info; + mmu_t *mmu = NULL; + int pm_handle=-1, rc; + + unsigned long nr_pt_pages; + unsigned long ppt_alloc; + unsigned long *physmap, *physmap_e, physmap_pfn; + + unsigned long v_start; + unsigned long vkern_start; + unsigned long vkern_entry; + unsigned long vkern_end; + unsigned long vinitrd_start; + unsigned long vinitrd_end; + unsigned long vphysmap_start; + unsigned long vphysmap_end; + unsigned long vstartinfo_start; + unsigned long vstartinfo_end; + unsigned long vstack_start; + unsigned long vstack_end; + unsigned long vpt_start; + unsigned long vpt_end; + unsigned long v_end; + + rc = readelfimage_base_and_size(image, image_size, + &vkern_start, &vkern_end, &vkern_entry); + if ( rc != 0 ) + goto error_out; + + /* + * Why do we need this? The number of page-table frames depends on the + * size of the bootstrap address space. But the size of the address space + * depends on the number of page-table frames (since each one is mapped + * read-only). We have a pair of simultaneous equations in two unknowns, + * which we solve by exhaustive search. + */ + for ( nr_pt_pages = 2; ; nr_pt_pages++ ) + { + v_start = vkern_start & ~((1<<22)-1); + vinitrd_start = round_pgup(vkern_end); + vinitrd_end = vinitrd_start + initrd_len; + vphysmap_start = round_pgup(vinitrd_end); + vphysmap_end = vphysmap_start + (nr_pages * sizeof(unsigned long)); + vpt_start = round_pgup(vphysmap_end); + vpt_end = vpt_start + (nr_pt_pages * PAGE_SIZE); + vstartinfo_start = vpt_end; + vstartinfo_end = vstartinfo_start + PAGE_SIZE; + vstack_start = vstartinfo_end; + vstack_end = vstack_start + PAGE_SIZE; + v_end = (vstack_end + (1<<22)-1) & ~((1<<22)-1); + if ( (v_end - vstack_end) < (512 << 10) ) + v_end += 1 << 22; /* Add extra 4MB to get >= 512kB padding. */ + if ( (((v_end - v_start) >> L2_PAGETABLE_SHIFT) + 1) <= nr_pt_pages ) + break; + } + + if ( (v_end - v_start) > (nr_pages * PAGE_SIZE) ) + { + printf("Initial guest OS requires too much space\n" + "(%luMB is greater than %luMB limit)\n", + (v_end-v_start)>>20, (nr_pages<>20); + goto error_out; + } + + printf("VIRTUAL MEMORY ARRANGEMENT:\n" + " Loaded kernel: %08lx->%08lx\n" + " Init. ramdisk: %08lx->%08lx\n" + " Phys-Mach map: %08lx->%08lx\n" + " Page tables: %08lx->%08lx\n" + " Start info: %08lx->%08lx\n" + " Boot stack: %08lx->%08lx\n" + " TOTAL: %08lx->%08lx\n", + vkern_start, vkern_end, + vinitrd_start, vinitrd_end, + vphysmap_start, vphysmap_end, + vpt_start, vpt_end, + vstartinfo_start, vstartinfo_end, + vstack_start, vstack_end, + v_start, v_end); + printf(" ENTRY ADDRESS: %08lx\n", vkern_entry); + + if ( (pm_handle = init_pfn_mapper((domid_t)dom)) < 0 ) + goto error_out; + + if ( (page_array = malloc(nr_pages * sizeof(unsigned long))) == NULL ) + { + PERROR("Could not allocate memory"); + goto error_out; + } + + if ( get_pfn_list(xc_handle, dom, page_array, nr_pages) != nr_pages ) + { + PERROR("Could not get the page frame list"); + goto error_out; + } + + loadelfimage(image, pm_handle, page_array, v_start); + + /* Load the initial ramdisk image. */ + if ( initrd_len != 0 ) + { + for ( i = (vinitrd_start - v_start); + i < (vinitrd_end - v_start); i += PAGE_SIZE ) + { + char page[PAGE_SIZE]; + if ( gzread(initrd_gfd, page, PAGE_SIZE) == -1 ) + { + PERROR("Error reading initrd image, could not"); + goto error_out; + } + copy_to_domain_page(pm_handle, + page_array[i>>PAGE_SHIFT], page); + } + } + + if ( (mmu = init_mmu_updates(xc_handle, dom)) == NULL ) + goto error_out; + + /* First allocate page for page dir. */ + ppt_alloc = (vpt_start - v_start) >> PAGE_SHIFT; + l2tab = page_array[ppt_alloc++] << PAGE_SHIFT; + ctxt->pt_base = l2tab; + + /* Initialise the page tables. */ + if ( (vl2tab = map_pfn_writeable(pm_handle, l2tab >> PAGE_SHIFT)) == NULL ) + goto error_out; + memset(vl2tab, 0, PAGE_SIZE); + vl2e = &vl2tab[l2_table_offset(v_start)]; + for ( count = 0; count < ((v_end-v_start)>>PAGE_SHIFT); count++ ) + { + if ( ((unsigned long)vl1e & (PAGE_SIZE-1)) == 0 ) + { + l1tab = page_array[ppt_alloc++] << PAGE_SHIFT; + if ( vl1tab != NULL ) + unmap_pfn(pm_handle, vl1tab); + if ( (vl1tab = map_pfn_writeable(pm_handle, + l1tab >> PAGE_SHIFT)) == NULL ) + goto error_out; + memset(vl1tab, 0, PAGE_SIZE); + vl1e = &vl1tab[l1_table_offset(v_start + (count<= ((vpt_start-v_start)>>PAGE_SHIFT)) && + (count < ((vpt_end -v_start)>>PAGE_SHIFT)) ) + *vl1e &= ~_PAGE_RW; + vl1e++; + } + unmap_pfn(pm_handle, vl1tab); + unmap_pfn(pm_handle, vl2tab); + + /* Write the phys->machine and machine->phys table entries. */ + physmap_pfn = (vphysmap_start - v_start) >> PAGE_SHIFT; + physmap = physmap_e = + map_pfn_writeable(pm_handle, page_array[physmap_pfn++]); + for ( count = 0; count < nr_pages; count++ ) + { + if ( add_mmu_update(xc_handle, mmu, + (page_array[count] << PAGE_SHIFT) | + MMU_MACHPHYS_UPDATE, count) ) + goto error_out; + *physmap_e++ = page_array[count]; + if ( ((unsigned long)physmap_e & (PAGE_SIZE-1)) == 0 ) + { + unmap_pfn(pm_handle, physmap); + physmap = physmap_e = + map_pfn_writeable(pm_handle, page_array[physmap_pfn++]); + } + } + unmap_pfn(pm_handle, physmap); + + /* + * Pin down l2tab addr as page dir page - causes hypervisor to provide + * correct protection for the page + */ + if ( add_mmu_update(xc_handle, mmu, + l2tab | MMU_EXTENDED_COMMAND, MMUEXT_PIN_L2_TABLE) ) + goto error_out; + + start_info = map_pfn_writeable( + pm_handle, page_array[(vstartinfo_start-v_start)>>PAGE_SHIFT]); + memset(start_info, 0, sizeof(*start_info)); + start_info->nr_pages = nr_pages; + start_info->shared_info = shared_info_frame << PAGE_SHIFT; + start_info->flags = flags; + start_info->pt_base = vpt_start; + start_info->nr_pt_frames = nr_pt_pages; + start_info->mfn_list = vphysmap_start; + start_info->domain_controller_evtchn = control_evtchn; + if ( initrd_len != 0 ) + { + start_info->mod_start = vinitrd_start; + start_info->mod_len = initrd_len; + } + strncpy(start_info->cmd_line, cmdline, MAX_CMDLINE); + start_info->cmd_line[MAX_CMDLINE-1] = '\0'; + unmap_pfn(pm_handle, start_info); + + /* shared_info page starts its life empty. */ + shared_info = map_pfn_writeable(pm_handle, shared_info_frame); + memset(shared_info, 0, sizeof(shared_info_t)); + /* Mask all upcalls... */ + for ( i = 0; i < MAX_VIRT_CPUS; i++ ) + shared_info->vcpu_data[i].evtchn_upcall_mask = 1; + unmap_pfn(pm_handle, shared_info); + + /* Send the page update requests down to the hypervisor. */ + if ( finish_mmu_updates(xc_handle, mmu) ) + goto error_out; + + free(mmu); + (void)close_pfn_mapper(pm_handle); + free(page_array); + + *pvsi = vstartinfo_start; + *pvke = vkern_entry; + + return 0; + + error_out: + if ( mmu != NULL ) + free(mmu); + if ( pm_handle >= 0 ) + (void)close_pfn_mapper(pm_handle); + if ( page_array != NULL ) + free(page_array); + return -1; +} + +static unsigned long get_filesz(int fd) +{ + u16 sig; + u32 _sz = 0; + unsigned long sz; + + lseek(fd, 0, SEEK_SET); + read(fd, &sig, sizeof(sig)); + sz = lseek(fd, 0, SEEK_END); + if ( sig == 0x8b1f ) /* GZIP signature? */ + { + lseek(fd, -4, SEEK_END); + read(fd, &_sz, 4); + sz = _sz; + } + lseek(fd, 0, SEEK_SET); + + return sz; +} + +static char *read_kernel_image(const char *filename, unsigned long *size) +{ + int kernel_fd = -1; + gzFile kernel_gfd = NULL; + char *image = NULL; + unsigned int bytes; + + if ( (kernel_fd = open(filename, O_RDONLY)) < 0 ) + { + PERROR("Could not open kernel image"); + goto out; + } + + *size = get_filesz(kernel_fd); + + if ( (kernel_gfd = gzdopen(kernel_fd, "rb")) == NULL ) + { + PERROR("Could not allocate decompression state for state file"); + goto out; + } + + if ( (image = malloc(*size)) == NULL ) + { + PERROR("Could not allocate memory for kernel image"); + goto out; + } + + if ( (bytes = gzread(kernel_gfd, image, *size)) != *size ) + { + PERROR("Error reading kernel image, could not" + " read the whole image (%d != %ld).", bytes, *size); + free(image); + image = NULL; + } + + out: + if ( kernel_gfd != NULL ) + gzclose(kernel_gfd); + else if ( kernel_fd >= 0 ) + close(kernel_fd); + return image; +} + +int xc_linux_build(int xc_handle, + u32 domid, + const char *image_name, + const char *ramdisk_name, + const char *cmdline, + unsigned int control_evtchn, + unsigned long flags) +{ + dom0_op_t launch_op, op; + int initrd_fd = -1; + gzFile initrd_gfd = NULL; + int rc, i; + full_execution_context_t st_ctxt, *ctxt = &st_ctxt; + unsigned long nr_pages; + char *image = NULL; + unsigned long image_size, initrd_size=0; + unsigned long vstartinfo_start, vkern_entry; + + if ( (nr_pages = get_tot_pages(xc_handle, domid)) < 0 ) + { + PERROR("Could not find total pages for domain"); + goto error_out; + } + + if ( (image = read_kernel_image(image_name, &image_size)) == NULL ) + goto error_out; + + if ( (ramdisk_name != NULL) && (strlen(ramdisk_name) != 0) ) + { + if ( (initrd_fd = open(ramdisk_name, O_RDONLY)) < 0 ) + { + PERROR("Could not open the initial ramdisk image"); + goto error_out; + } + + initrd_size = get_filesz(initrd_fd); + + if ( (initrd_gfd = gzdopen(initrd_fd, "rb")) == NULL ) + { + PERROR("Could not allocate decompression state for initrd"); + goto error_out; + } + } + + if ( mlock(&st_ctxt, sizeof(st_ctxt) ) ) + { + PERROR("Unable to mlock ctxt"); + return 1; + } + + op.cmd = DOM0_GETDOMAININFO; + op.u.getdomaininfo.domain = (domid_t)domid; + op.u.getdomaininfo.ctxt = ctxt; + if ( (do_dom0_op(xc_handle, &op) < 0) || + ((u32)op.u.getdomaininfo.domain != domid) ) + { + PERROR("Could not get info on domain"); + goto error_out; + } + if ( !(op.u.getdomaininfo.flags & DOMFLAGS_PAUSED) || + (ctxt->pt_base != 0) ) + { + ERROR("Domain is already constructed"); + goto error_out; + } + + if ( setup_guestos(xc_handle, domid, image, image_size, + initrd_gfd, initrd_size, nr_pages, + &vstartinfo_start, &vkern_entry, + ctxt, cmdline, + op.u.getdomaininfo.shared_info_frame, + control_evtchn, flags) < 0 ) + { + ERROR("Error constructing guest OS"); + goto error_out; + } + + if ( initrd_fd >= 0 ) + close(initrd_fd); + if ( initrd_gfd ) + gzclose(initrd_gfd); + if ( image != NULL ) + free(image); + + ctxt->flags = 0; + + /* + * Initial register values: + * DS,ES,FS,GS = FLAT_GUESTOS_DS + * CS:EIP = FLAT_GUESTOS_CS:start_pc + * SS:ESP = FLAT_GUESTOS_DS:start_stack + * ESI = start_info + * [EAX,EBX,ECX,EDX,EDI,EBP are zero] + * EFLAGS = IF | 2 (bit 1 is reserved and should always be 1) + */ + ctxt->cpu_ctxt.ds = FLAT_GUESTOS_DS; + ctxt->cpu_ctxt.es = FLAT_GUESTOS_DS; + ctxt->cpu_ctxt.fs = FLAT_GUESTOS_DS; + ctxt->cpu_ctxt.gs = FLAT_GUESTOS_DS; + ctxt->cpu_ctxt.ss = FLAT_GUESTOS_DS; + ctxt->cpu_ctxt.cs = FLAT_GUESTOS_CS; + ctxt->cpu_ctxt.eip = vkern_entry; + ctxt->cpu_ctxt.esp = vstartinfo_start; + ctxt->cpu_ctxt.esi = vstartinfo_start; + ctxt->cpu_ctxt.eflags = (1<<9) | (1<<2); + + /* FPU is set up to default initial state. */ + memset(ctxt->fpu_ctxt, 0, sizeof(ctxt->fpu_ctxt)); + + /* Virtual IDT is empty at start-of-day. */ + for ( i = 0; i < 256; i++ ) + { + ctxt->trap_ctxt[i].vector = i; + ctxt->trap_ctxt[i].cs = FLAT_GUESTOS_CS; + } + ctxt->fast_trap_idx = 0; + + /* No LDT. */ + ctxt->ldt_ents = 0; + + /* Use the default Xen-provided GDT. */ + ctxt->gdt_ents = 0; + + /* Ring 1 stack is the initial stack. */ + ctxt->guestos_ss = FLAT_GUESTOS_DS; + ctxt->guestos_esp = vstartinfo_start; + + /* No debugging. */ + memset(ctxt->debugreg, 0, sizeof(ctxt->debugreg)); + + /* No callback handlers. */ + ctxt->event_callback_cs = FLAT_GUESTOS_CS; + ctxt->event_callback_eip = 0; + ctxt->failsafe_callback_cs = FLAT_GUESTOS_CS; + ctxt->failsafe_callback_eip = 0; + + memset( &launch_op, 0, sizeof(launch_op) ); + + launch_op.u.builddomain.domain = (domid_t)domid; + launch_op.u.builddomain.ctxt = ctxt; + + launch_op.cmd = DOM0_BUILDDOMAIN; + rc = do_dom0_op(xc_handle, &launch_op); + + return rc; + + error_out: + if ( initrd_gfd != NULL ) + gzclose(initrd_gfd); + else if ( initrd_fd >= 0 ) + close(initrd_fd); + if ( image != NULL ) + free(image); + + return -1; +} + +static inline int is_loadable_phdr(Elf_Phdr *phdr) +{ + return ((phdr->p_type == PT_LOAD) && + ((phdr->p_flags & (PF_W|PF_X)) != 0)); +} + +static int readelfimage_base_and_size(char *elfbase, + unsigned long elfsize, + unsigned long *pkernstart, + unsigned long *pkernend, + unsigned long *pkernentry) +{ + Elf_Ehdr *ehdr = (Elf_Ehdr *)elfbase; + Elf_Phdr *phdr; + Elf_Shdr *shdr; + unsigned long kernstart = ~0UL, kernend=0UL; + char *shstrtab, *guestinfo; + int h; + + if ( !IS_ELF(*ehdr) ) + { + ERROR("Kernel image does not have an ELF header."); + return -EINVAL; + } + + if ( (ehdr->e_phoff + (ehdr->e_phnum * ehdr->e_phentsize)) > elfsize ) + { + ERROR("ELF program headers extend beyond end of image."); + return -EINVAL; + } + + if ( (ehdr->e_shoff + (ehdr->e_shnum * ehdr->e_shentsize)) > elfsize ) + { + ERROR("ELF section headers extend beyond end of image."); + return -EINVAL; + } + + /* Find the section-header strings table. */ + if ( ehdr->e_shstrndx == SHN_UNDEF ) + { + ERROR("ELF image has no section-header strings table (shstrtab)."); + return -EINVAL; + } + shdr = (Elf_Shdr *)(elfbase + ehdr->e_shoff + + (ehdr->e_shstrndx*ehdr->e_shentsize)); + shstrtab = elfbase + shdr->sh_offset; + + /* Find the special '__xen_guest' section and check its contents. */ + for ( h = 0; h < ehdr->e_shnum; h++ ) + { + shdr = (Elf_Shdr *)(elfbase + ehdr->e_shoff + (h*ehdr->e_shentsize)); + if ( strcmp(&shstrtab[shdr->sh_name], "__xen_guest") != 0 ) + continue; + guestinfo = elfbase + shdr->sh_offset; + if ( (strstr(guestinfo, "GUEST_OS=linux") == NULL) || + (strstr(guestinfo, "XEN_VER=1.3") == NULL) ) + { + ERROR("Will only load Linux images built for Xen v1.3"); + ERROR("Actually saw: '%s'", guestinfo); + return -EINVAL; + } + break; + } + if ( h == ehdr->e_shnum ) + { + ERROR("Not a Xen-ELF image: '__xen_guest' section not found."); + return -EINVAL; + } + + for ( h = 0; h < ehdr->e_phnum; h++ ) + { + phdr = (Elf_Phdr *)(elfbase + ehdr->e_phoff + (h*ehdr->e_phentsize)); + if ( !is_loadable_phdr(phdr) ) + continue; + if ( phdr->p_vaddr < kernstart ) + kernstart = phdr->p_vaddr; + if ( (phdr->p_vaddr + phdr->p_memsz) > kernend ) + kernend = phdr->p_vaddr + phdr->p_memsz; + } + + if ( (kernstart > kernend) || + (ehdr->e_entry < kernstart) || + (ehdr->e_entry > kernend) ) + { + ERROR("Malformed ELF image."); + return -EINVAL; + } + + *pkernstart = kernstart; + *pkernend = kernend; + *pkernentry = ehdr->e_entry; + + return 0; +} + +static int loadelfimage(char *elfbase, int pmh, unsigned long *parray, + unsigned long vstart) +{ + Elf_Ehdr *ehdr = (Elf_Ehdr *)elfbase; + Elf_Phdr *phdr; + int h; + + char *va; + unsigned long pa, done, chunksz; + + for ( h = 0; h < ehdr->e_phnum; h++ ) + { + phdr = (Elf_Phdr *)(elfbase + ehdr->e_phoff + (h*ehdr->e_phentsize)); + if ( !is_loadable_phdr(phdr) ) + continue; + + for ( done = 0; done < phdr->p_filesz; done += chunksz ) + { + pa = (phdr->p_vaddr + done) - vstart; + va = map_pfn_writeable(pmh, parray[pa>>PAGE_SHIFT]); + va += pa & (PAGE_SIZE-1); + chunksz = phdr->p_filesz - done; + if ( chunksz > (PAGE_SIZE - (pa & (PAGE_SIZE-1))) ) + chunksz = PAGE_SIZE - (pa & (PAGE_SIZE-1)); + memcpy(va, elfbase + phdr->p_offset + done, chunksz); + unmap_pfn(pmh, va); + } + + for ( ; done < phdr->p_memsz; done += chunksz ) + { + pa = (phdr->p_vaddr + done) - vstart; + va = map_pfn_writeable(pmh, parray[pa>>PAGE_SHIFT]); + va += pa & (PAGE_SIZE-1); + chunksz = phdr->p_memsz - done; + if ( chunksz > (PAGE_SIZE - (pa & (PAGE_SIZE-1))) ) + chunksz = PAGE_SIZE - (pa & (PAGE_SIZE-1)); + memset(va, 0, chunksz); + unmap_pfn(pmh, va); + } + } + + return 0; +} + diff --git a/tools/libxc/xc_linux_restore.c b/tools/libxc/xc_linux_restore.c new file mode 100644 index 0000000000..badba75162 --- /dev/null +++ b/tools/libxc/xc_linux_restore.c @@ -0,0 +1,600 @@ +/****************************************************************************** + * xc_linux_restore.c + * + * Restore the state of a Linux session. + * + * Copyright (c) 2003, K A Fraser. + */ + +#include "xc_private.h" +#include + +#define MAX_BATCH_SIZE 1024 + +#define DEBUG 0 + +#if DEBUG +#define DPRINTF(_f, _a...) printf ( _f , ## _a ) +#else +#define DPRINTF(_f, _a...) ((void)0) +#endif + + +static int get_pfn_list(int xc_handle, + u32 domain_id, + unsigned long *pfn_buf, + unsigned long max_pfns) +{ + dom0_op_t op; + int ret; + op.cmd = DOM0_GETMEMLIST; + op.u.getmemlist.domain = (domid_t)domain_id; + op.u.getmemlist.max_pfns = max_pfns; + op.u.getmemlist.buffer = pfn_buf; + + if ( mlock(pfn_buf, max_pfns * sizeof(unsigned long)) != 0 ) + { + PERROR("Could not lock pfn list buffer"); + return -1; + } + + ret = do_dom0_op(xc_handle, &op); + + (void)munlock(pfn_buf, max_pfns * sizeof(unsigned long)); + + return (ret < 0) ? -1 : op.u.getmemlist.num_pfns; +} + +/** Read the vmconfig string from the state input. + * It is stored as a 4-byte count 'n' followed by n bytes. + * The config data is stored in a new string in 'ioctxt->vmconfig', + * and is null-terminated. The count is stored in 'ioctxt->vmconfig_n'. + * + * @param ioctxt i/o context + * @return 0 on success, non-zero on error. + */ +static int read_vmconfig(XcIOContext *ioctxt){ + int err = -1; + if(xcio_read(ioctxt, &ioctxt->vmconfig_n, sizeof(ioctxt->vmconfig_n))){ + goto exit; + } + ioctxt->vmconfig = malloc(ioctxt->vmconfig_n + 1); + if(!ioctxt->vmconfig) goto exit; + if(xcio_read(ioctxt, ioctxt->vmconfig, ioctxt->vmconfig_n)){ + goto exit; + } + ioctxt->vmconfig[ioctxt->vmconfig_n] = '\0'; + err = 0; + exit: + if(err){ + if(ioctxt->vmconfig){ + free(ioctxt->vmconfig); + } + ioctxt->vmconfig = NULL; + ioctxt->vmconfig_n = 0; + } + return err; +} + +int xc_linux_restore(int xc_handle, XcIOContext *ioctxt) +{ + dom0_op_t op; + int rc = 1, i, n, k; + unsigned long mfn, pfn, xpfn; + unsigned int prev_pc, this_pc; + u32 dom = ioctxt->domain; + int verify = 0; + + /* Number of page frames in use by this Linux session. */ + unsigned long nr_pfns; + + /* The new domain's shared-info frame number. */ + unsigned long shared_info_frame; + unsigned char shared_info[PAGE_SIZE]; /* saved contents from file */ + + /* A copy of the CPU context of the guest. */ + full_execution_context_t ctxt; + + /* First 16 bytes of the state file must contain 'LinuxGuestRecord'. */ + char signature[16]; + + /* A copy of the domain's name. */ + char name[MAX_DOMAIN_NAME]; + + /* A table containg the type of each PFN (/not/ MFN!). */ + unsigned long *pfn_type = NULL; + + /* A table of MFNs to map in the current region */ + unsigned long *region_mfn = NULL; + + /* A temporary mapping, and a copy, of one frame of guest memory. */ + unsigned long *ppage; + + /* A copy of the pfn-to-mfn table frame list. */ + unsigned long pfn_to_mfn_frame_list[1024]; + + /* A table mapping each PFN to its new MFN. */ + unsigned long *pfn_to_mfn_table = NULL; + + /* used by mapper for updating the domain's copy of the table */ + unsigned long *live_pfn_to_mfn_table = NULL; + + /* A temporary mapping of the guest's suspend record. */ + suspend_record_t *p_srec; + + char *region_base; + + mmu_t *mmu = NULL; + + int pm_handle = -1; + + /* used by debug verify code */ + unsigned long buf[PAGE_SIZE/sizeof(unsigned long)]; + + if ( mlock(&ctxt, sizeof(ctxt) ) ) { + /* needed for when we do the build dom0 op, + but might as well do early */ + PERROR("Unable to mlock ctxt"); + return 1; + } + + /* Start writing out the saved-domain record. */ + if ( xcio_read(ioctxt, signature, 16) || + (memcmp(signature, "LinuxGuestRecord", 16) != 0) ) { + xcio_error(ioctxt, "Unrecognised state format -- no signature found"); + goto out; + } + + if ( xcio_read(ioctxt, name, sizeof(name)) || + xcio_read(ioctxt, &nr_pfns, sizeof(unsigned long)) || + xcio_read(ioctxt, pfn_to_mfn_frame_list, PAGE_SIZE) ) { + xcio_error(ioctxt, "Error reading header"); + goto out; + } + + if(read_vmconfig(ioctxt)){ + xcio_error(ioctxt, "Error writing vmconfig"); + goto out; + } + + for ( i = 0; i < MAX_DOMAIN_NAME; i++ ) { + if ( name[i] == '\0' ) break; + if ( name[i] & 0x80 ) + { + xcio_error(ioctxt, "Random characters in domain name"); + goto out; + } + } + name[MAX_DOMAIN_NAME-1] = '\0'; + + if ( nr_pfns > 1024*1024 ) { + xcio_error(ioctxt, "Invalid state file -- pfn count out of range"); + goto out; + } + + /* We want zeroed memory so use calloc rather than malloc. */ + pfn_to_mfn_table = calloc(1, 4 * nr_pfns); + pfn_type = calloc(1, 4 * nr_pfns); + region_mfn = calloc(1, 4 * MAX_BATCH_SIZE); + + if ( (pfn_to_mfn_table == NULL) || (pfn_type == NULL) || + (region_mfn == NULL) ) { + errno = ENOMEM; + goto out; + } + + if ( mlock(region_mfn, 4 * MAX_BATCH_SIZE ) ) { + xcio_error(ioctxt, "Could not mlock region_mfn"); + goto out; + } + + /* Set the domain's name to that from the restore file */ + if ( xc_domain_setname( xc_handle, dom, name ) ) { + xcio_error(ioctxt, "Could not set domain name"); + goto out; + } + + /* Set the domain's initial memory allocation + to that from the restore file */ + + if ( xc_domain_setinitialmem(xc_handle, dom, + nr_pfns * (PAGE_SIZE / 1024)) ) + { + xcio_error(ioctxt, "Could not set domain initial memory"); + goto out; + } + + /* Get the domain's shared-info frame. */ + op.cmd = DOM0_GETDOMAININFO; + op.u.getdomaininfo.domain = (domid_t)dom; + op.u.getdomaininfo.ctxt = NULL; + if ( do_dom0_op(xc_handle, &op) < 0 ) { + xcio_error(ioctxt, "Could not get information on new domain"); + goto out; + } + shared_info_frame = op.u.getdomaininfo.shared_info_frame; + + if ( (pm_handle = init_pfn_mapper((domid_t)dom)) < 0 ) + goto out; + + + + /* Build the pfn-to-mfn table. We choose MFN ordering returned by Xen. */ + if ( get_pfn_list(xc_handle, dom, pfn_to_mfn_table, nr_pfns) != nr_pfns ) { + xcio_error(ioctxt, "Did not read correct number of frame numbers for new dom"); + goto out; + } + + if ( (mmu = init_mmu_updates(xc_handle, dom)) == NULL ) { + xcio_error(ioctxt, "Could not initialise for MMU updates"); + goto out; + } + + xcio_info(ioctxt, "Reloading memory pages: 0%%"); + + /* + * Now simply read each saved frame into its new machine frame. + * We uncanonicalise page tables as we go. + */ + prev_pc = 0; + + n=0; + while(1) { + int j; + unsigned long region_pfn_type[MAX_BATCH_SIZE]; + + this_pc = (n * 100) / nr_pfns; + if ( (this_pc - prev_pc) >= 5 ) { + xcio_info(ioctxt, "\b\b\b\b%3d%%", this_pc); + prev_pc = this_pc; + } + + if ( xcio_read(ioctxt, &j, sizeof(int)) ) { + xcio_error(ioctxt, "Error when reading from state file"); + goto out; + } + + DPRINTF("batch %d\n",j); + + if ( j == -1 ) { + verify = 1; + printf("Entering page verify mode\n"); + continue; + } + + if ( j == 0 ) break; /* our work here is done */ + + if( j > MAX_BATCH_SIZE ) { + xcio_error(ioctxt, "Max batch size exceeded. Giving up."); + goto out; + } + + if ( xcio_read(ioctxt, region_pfn_type, j*sizeof(unsigned long)) ) { + xcio_error(ioctxt, "Error when reading from state file"); + goto out; + } + + for(i=0; inr_pfns) { + xcio_error(ioctxt, "pfn out of range"); + goto out; + } + + region_pfn_type[i] &= LTAB_MASK; + + pfn_type[pfn] = region_pfn_type[i]; + + mfn = pfn_to_mfn_table[pfn]; + + if ( verify ) { + ppage = (unsigned long*) buf; /* debug case */ + } else { + ppage = (unsigned long*) (region_base + i*PAGE_SIZE); + } + + if ( xcio_read(ioctxt, ppage, PAGE_SIZE) ) { + xcio_error(ioctxt, "Error when reading from state file"); + goto out; + } + + switch( region_pfn_type[i] ) { + case 0: + break; + + case L1TAB: + { + for ( k = 0; k < 1024; k++ ) { + if ( ppage[k] & _PAGE_PRESENT ) { + xpfn = ppage[k] >> PAGE_SHIFT; + + if ( xpfn >= nr_pfns ) { + xcio_error(ioctxt, "Frame number in type %lu page table is " + "out of range. i=%d k=%d pfn=0x%lx " + "nr_pfns=%lu", region_pfn_type[i]>>28, i, + k, xpfn, nr_pfns); + goto out; + } + + ppage[k] &= (PAGE_SIZE - 1) & + ~(_PAGE_GLOBAL | _PAGE_PAT); + ppage[k] |= pfn_to_mfn_table[xpfn] << PAGE_SHIFT; + } + } + } + break; + + case L2TAB: + { + for ( k = 0; + k < (HYPERVISOR_VIRT_START>>L2_PAGETABLE_SHIFT); + k++ ) { + if ( ppage[k] & _PAGE_PRESENT ) { + xpfn = ppage[k] >> PAGE_SHIFT; + + if ( xpfn >= nr_pfns ) { + xcio_error(ioctxt, "Frame number in type %lu page table is " + "out of range. i=%d k=%d pfn=%lu nr_pfns=%lu", + region_pfn_type[i]>>28, i, k, xpfn, nr_pfns); + + goto out; + } + + ppage[k] &= (PAGE_SIZE - 1) & + ~(_PAGE_GLOBAL | _PAGE_PSE); + ppage[k] |= pfn_to_mfn_table[xpfn] << PAGE_SHIFT; + } + } + } + break; + + default: + xcio_error(ioctxt, "Bogus page type %lx page table is out of range." + " i=%d nr_pfns=%lu", region_pfn_type[i], i, nr_pfns); + goto out; + + } /* end of page type switch statement */ + + if ( verify ) { + int res = memcmp(buf, (region_base + i*PAGE_SIZE), PAGE_SIZE ); + if (res) { + int v; + printf("************** pfn=%lx type=%lx gotcs=%08lx " + "actualcs=%08lx\n", pfn, pfn_type[pfn], + csum_page(region_base + i*PAGE_SIZE), + csum_page(buf)); + for ( v = 0; v < 4; v++ ) { + unsigned long *p = (unsigned long *) + (region_base + i*PAGE_SIZE); + if ( buf[v] != p[v] ) + printf(" %d: %08lx %08lx\n", + v, buf[v], p[v] ); + } + } + } + + if ( add_mmu_update(xc_handle, mmu, + (mfn<= nr_pfns) || (pfn_type[pfn] != NOTAB) ) + { + xcio_error(ioctxt, "Suspend record frame number is bad"); + goto out; + } + ctxt.cpu_ctxt.esi = mfn = pfn_to_mfn_table[pfn]; + p_srec = map_pfn_writeable(pm_handle, mfn); + p_srec->resume_info.nr_pages = nr_pfns; + p_srec->resume_info.shared_info = shared_info_frame << PAGE_SHIFT; + p_srec->resume_info.flags = 0; + unmap_pfn(pm_handle, p_srec); + + /* Uncanonicalise each GDT frame number. */ + if ( ctxt.gdt_ents > 8192 ) { + xcio_error(ioctxt, "GDT entry count out of range"); + goto out; + } + for ( i = 0; i < ctxt.gdt_ents; i += 512 ) { + pfn = ctxt.gdt_frames[i]; + if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NOTAB) ) { + xcio_error(ioctxt, "GDT frame number is bad"); + goto out; + } + ctxt.gdt_frames[i] = pfn_to_mfn_table[pfn]; + } + + /* Uncanonicalise the page table base pointer. */ + pfn = ctxt.pt_base >> PAGE_SHIFT; + if ( (pfn >= nr_pfns) || (pfn_type[pfn] != L2TAB) ) { + printf("PT base is bad. pfn=%lu nr=%lu type=%08lx %08lx\n", + pfn, nr_pfns, pfn_type[pfn], (unsigned long)L2TAB); + xcio_error(ioctxt, "PT base is bad."); + goto out; + } + ctxt.pt_base = pfn_to_mfn_table[pfn] << PAGE_SHIFT; + + + /* clear any pending events and the selector */ + memset( &(((shared_info_t *)shared_info)->evtchn_pending[0]), + 0, sizeof (((shared_info_t *)shared_info)->evtchn_pending)+ + sizeof(((shared_info_t *)shared_info)->evtchn_pending_sel) ); + + /* Copy saved contents of shared-info page. No checking needed. */ + ppage = map_pfn_writeable(pm_handle, shared_info_frame); + memcpy(ppage, shared_info, sizeof(shared_info_t)); + unmap_pfn(pm_handle, ppage); + + + /* Uncanonicalise the pfn-to-mfn table frame-number list. */ + for ( i = 0; i < (nr_pfns+1023)/1024; i++ ) { + unsigned long pfn, mfn; + + pfn = pfn_to_mfn_frame_list[i]; + if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NOTAB) ) { + xcio_error(ioctxt, "PFN-to-MFN frame number is bad"); + goto out; + } + mfn = pfn_to_mfn_table[pfn]; + pfn_to_mfn_frame_list[i] = mfn; + } + + if ( (live_pfn_to_mfn_table = + mfn_mapper_map_batch(xc_handle, dom, + PROT_WRITE, + pfn_to_mfn_frame_list, + (nr_pfns+1023)/1024 )) == 0 ) { + xcio_error(ioctxt, "Couldn't map pfn_to_mfn table"); + goto out; + } + + memcpy( live_pfn_to_mfn_table, pfn_to_mfn_table, + nr_pfns*sizeof(unsigned long) ); + + munmap( live_pfn_to_mfn_table, ((nr_pfns+1023)/1024)*PAGE_SIZE ); + + /* + * Safety checking of saved context: + * 1. cpu_ctxt is fine, as Xen checks that on context switch. + * 2. fpu_ctxt is fine, as it can't hurt Xen. + * 3. trap_ctxt needs the code selectors checked. + * 4. fast_trap_idx is checked by Xen. + * 5. ldt base must be page-aligned, no more than 8192 ents, ... + * 6. gdt already done, and further checking is done by Xen. + * 7. check that guestos_ss is safe. + * 8. pt_base is already done. + * 9. debugregs are checked by Xen. + * 10. callback code selectors need checking. + */ + for ( i = 0; i < 256; i++ ) { + ctxt.trap_ctxt[i].vector = i; + if ( (ctxt.trap_ctxt[i].cs & 3) == 0 ) + ctxt.trap_ctxt[i].cs = FLAT_GUESTOS_CS; + } + if ( (ctxt.guestos_ss & 3) == 0 ){ + ctxt.guestos_ss = FLAT_GUESTOS_DS; + } + if ( (ctxt.event_callback_cs & 3) == 0 ){ + ctxt.event_callback_cs = FLAT_GUESTOS_CS; + } + if ( (ctxt.failsafe_callback_cs & 3) == 0 ){ + ctxt.failsafe_callback_cs = FLAT_GUESTOS_CS; + } + if ( ((ctxt.ldt_base & (PAGE_SIZE - 1)) != 0) || + (ctxt.ldt_ents > 8192) || + (ctxt.ldt_base > HYPERVISOR_VIRT_START) || + ((ctxt.ldt_base + ctxt.ldt_ents*8) > HYPERVISOR_VIRT_START) ) + { + xcio_error(ioctxt, "Bad LDT base or size"); + goto out; + } + + op.cmd = DOM0_BUILDDOMAIN; + op.u.builddomain.domain = (domid_t)dom; + op.u.builddomain.ctxt = &ctxt; + rc = do_dom0_op(xc_handle, &op); + + /* don't start the domain as we have console etc to set up */ + + if( rc == 0 ) { + /* Success: print the domain id. */ + xcio_info(ioctxt, "DOM=%lu\n", dom); + return 0; + } + + + out: + if ( (rc != 0) && (dom != 0) ){ + xc_domain_destroy(xc_handle, dom); + } + if ( mmu != NULL ){ + free(mmu); + } + if ( pm_handle >= 0 ){ + (void)close_pfn_mapper(pm_handle); + } + if ( pfn_to_mfn_table != NULL ){ + free(pfn_to_mfn_table); + } + if ( pfn_type != NULL ){ + free(pfn_type); + } + + if ( rc == 0 ){ + ioctxt->domain = dom; + } + DPRINTF("Restore exit with rc=%d\n",rc); + return rc; +} diff --git a/tools/libxc/xc_linux_save.c b/tools/libxc/xc_linux_save.c new file mode 100644 index 0000000000..c74e209bdc --- /dev/null +++ b/tools/libxc/xc_linux_save.c @@ -0,0 +1,840 @@ +/****************************************************************************** + * xc_linux_save.c + * + * Save the state of a running Linux session. + * + * Copyright (c) 2003, K A Fraser. + */ + +#include +#include "xc_private.h" +#include + +#define BATCH_SIZE 1024 /* 1024 pages (4MB) at a time */ + +#define DEBUG 0 +#define DDEBUG 0 + +#if DEBUG +#define DPRINTF(_f, _a...) printf ( _f , ## _a ) +#else +#define DPRINTF(_f, _a...) ((void)0) +#endif + +#if DDEBUG +#define DDPRINTF(_f, _a...) printf ( _f , ## _a ) +#else +#define DDPRINTF(_f, _a...) ((void)0) +#endif + +/* + * Returns TRUE if the given machine frame number has a unique mapping + * in the guest's pseudophysical map. + * 0x80000000-3 mark the shared_info, and blk/net rings + */ +#define MFN_IS_IN_PSEUDOPHYS_MAP(_mfn) \ + (((_mfn) < (1024*1024)) && \ + (((live_mfn_to_pfn_table[_mfn] < nr_pfns) && \ + (live_pfn_to_mfn_table[live_mfn_to_pfn_table[_mfn]] == (_mfn))) || \ + ((live_mfn_to_pfn_table[_mfn] >= 0x80000000) && \ + (live_mfn_to_pfn_table[_mfn] <= 0x80000003)) || \ + (live_pfn_to_mfn_table[live_mfn_to_pfn_table[_mfn]] == 0x80000004))) + +/* Returns TRUE if MFN is successfully converted to a PFN. */ +#define translate_mfn_to_pfn(_pmfn) \ +({ \ + unsigned long mfn = *(_pmfn); \ + int _res = 1; \ + if ( !MFN_IS_IN_PSEUDOPHYS_MAP(mfn) ) \ + _res = 0; \ + else \ + *(_pmfn) = live_mfn_to_pfn_table[mfn]; \ + _res; \ +}) + +static inline int test_bit ( int nr, volatile void * addr) +{ + return (((unsigned long*)addr)[nr/(sizeof(unsigned long)*8)] >> + (nr % (sizeof(unsigned long)*8))) & 1; +} + +static inline void clear_bit ( int nr, volatile void * addr) +{ + ((unsigned long*)addr)[nr/(sizeof(unsigned long)*8)] &= + ~(1 << (nr % (sizeof(unsigned long)*8) ) ); +} + +static inline void set_bit ( int nr, volatile void * addr) +{ + ((unsigned long*)addr)[nr/(sizeof(unsigned long)*8)] |= + (1 << (nr % (sizeof(unsigned long)*8) ) ); +} + +/* Returns the hamming weight (i.e. the number of bits set) in a N-bit word */ +static inline unsigned int hweight32(unsigned int w) +{ + unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555); + res = (res & 0x33333333) + ((res >> 2) & 0x33333333); + res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F); + res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF); + return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF); +} + +static inline int count_bits ( int nr, volatile void *addr) +{ + int i, count = 0; + unsigned long *p = (unsigned long *)addr; + /* We know that the array is padded to unsigned long. */ + for(i=0;ioder 15->4 16->4 17->5 */ + /* 512MB domain, 128k pages, order 17 */ + + /* + QPONMLKJIHGFEDCBA + QPONMLKJIH + GFEDCBA + */ + + /* + QPONMLKJIHGFEDCBA + EDCBA + QPONM + LKJIHGF + */ + + do { i = ((i>>(order_nr-10)) | ( i<<10 ) ) & ((1<= nr ); /* this won't ever loop if nr is a power of 2 */ + + return i; +} + +static long long tv_to_us( struct timeval *new ) +{ + return (new->tv_sec * 1000000) + new->tv_usec; +} + +static long long llgettimeofday() +{ + struct timeval now; + gettimeofday(&now, NULL); + return tv_to_us(&now); +} + +static long long tv_delta( struct timeval *new, struct timeval *old ) +{ + return ((new->tv_sec - old->tv_sec)*1000000 ) + + (new->tv_usec - old->tv_usec); +} + +static int print_stats( int xc_handle, u32 domid, + int pages_sent, xc_shadow_control_stats_t *stats, + int print ) +{ + static struct timeval wall_last; + static long long d0_cpu_last; + static long long d1_cpu_last; + + struct timeval wall_now; + long long wall_delta; + long long d0_cpu_now, d0_cpu_delta; + long long d1_cpu_now, d1_cpu_delta; + + gettimeofday(&wall_now, NULL); + + d0_cpu_now = xc_domain_get_cpu_usage( xc_handle, 0 )/1000; + d1_cpu_now = xc_domain_get_cpu_usage( xc_handle, domid )/1000; + + if ( (d0_cpu_now == -1) || (d1_cpu_now == -1) ) + printf("ARRHHH!!\n"); + + wall_delta = tv_delta(&wall_now,&wall_last)/1000; + + if ( wall_delta == 0 ) wall_delta = 1; + + d0_cpu_delta = (d0_cpu_now - d0_cpu_last)/1000; + d1_cpu_delta = (d1_cpu_now - d1_cpu_last)/1000; + + if ( print ) + printf("delta %lldms, dom0 %d%%, target %d%%, sent %dMb/s, " + "dirtied %dMb/s\n", + wall_delta, + (int)((d0_cpu_delta*100)/wall_delta), + (int)((d1_cpu_delta*100)/wall_delta), + (int)((pages_sent*PAGE_SIZE*8)/(wall_delta*1000)), + (int)((stats->dirty_count*PAGE_SIZE*8)/(wall_delta*1000))); + + d0_cpu_last = d0_cpu_now; + d1_cpu_last = d1_cpu_now; + wall_last = wall_now; + + return 0; +} + +/** Write the vmconfig string. + * It is stored as a 4-byte count 'n' followed by n bytes. + * + * @param ioctxt i/o context + * @return 0 on success, non-zero on error. + */ +static int write_vmconfig(XcIOContext *ioctxt){ + int err = -1; + if(xcio_write(ioctxt, &ioctxt->vmconfig_n, sizeof(ioctxt->vmconfig_n))) goto exit; + if(xcio_write(ioctxt, ioctxt->vmconfig, ioctxt->vmconfig_n)) goto exit; + err = 0; + exit: + return err; +} + +static int analysis_phase( int xc_handle, u32 domid, + int nr_pfns, unsigned long *arr ) +{ + long long start, now; + xc_shadow_control_stats_t stats; + + start = llgettimeofday(); + + while ( 0 ) + { + int i; + + xc_shadow_control( xc_handle, domid, + DOM0_SHADOW_CONTROL_OP_CLEAN2, + arr, nr_pfns, NULL); + printf("#Flush\n"); + for ( i = 0; i < 100; i++ ) + { + usleep(10000); + now = llgettimeofday(); + xc_shadow_control( xc_handle, domid, + DOM0_SHADOW_CONTROL_OP_PEEK, + NULL, 0, &stats); + + printf("now= %lld faults= %ld dirty= %ld dirty_net= %ld " + "dirty_block= %ld\n", + ((now-start)+500)/1000, + stats.fault_count, stats.dirty_count, + stats.dirty_net_count, stats.dirty_block_count); + } + } + + return -1; +} + +int xc_linux_save(int xc_handle, XcIOContext *ioctxt) +{ + dom0_op_t op; + int rc = 1, i, j, k, last_iter, iter = 0; + unsigned long mfn; + u32 domid = ioctxt->domain; + int live = (ioctxt->flags & XCFLAGS_LIVE); + int debug = (ioctxt->flags & XCFLAGS_DEBUG); + int sent_last_iter, skip_this_iter; + + /* Important tuning parameters */ + int max_iters = 29; /* limit us to 30 times round loop */ + int max_factor = 3; /* never send more than 3x nr_pfns */ + + /* The new domain's shared-info frame number. */ + unsigned long shared_info_frame; + + /* A copy of the CPU context of the guest. */ + full_execution_context_t ctxt; + + /* A copy of the domain's name. */ + char name[MAX_DOMAIN_NAME]; + + /* A table containg the type of each PFN (/not/ MFN!). */ + unsigned long *pfn_type = NULL; + unsigned long *pfn_batch = NULL; + + /* A temporary mapping, and a copy, of one frame of guest memory. */ + unsigned long page[1024]; + + /* A copy of the pfn-to-mfn table frame list. */ + unsigned long *live_pfn_to_mfn_frame_list; + unsigned long pfn_to_mfn_frame_list[1024]; + + /* Live mapping of the table mapping each PFN to its current MFN. */ + unsigned long *live_pfn_to_mfn_table = NULL; + /* Live mapping of system MFN to PFN table. */ + unsigned long *live_mfn_to_pfn_table = NULL; + + /* Live mapping of shared info structure */ + unsigned long *live_shinfo; + + /* base of the region in which domain memory is mapped */ + unsigned char *region_base = NULL; + + /* A temporary mapping, and a copy, of the guest's suspend record. */ + suspend_record_t *p_srec; + + /* number of pages we're dealing with */ + unsigned long nr_pfns; + + /* power of 2 order of nr_pfns */ + int order_nr; + + /* bitmap of pages: + - that should be sent this iteration (unless later marked as skip); + - to skip this iteration because already dirty; + - to fixup by sending at the end if not already resent; */ + unsigned long *to_send, *to_skip, *to_fix; + + xc_shadow_control_stats_t stats; + + int needed_to_fix = 0; + int total_sent = 0; + + if (mlock(&ctxt, sizeof(ctxt))) { + xcio_perror(ioctxt, "Unable to mlock ctxt"); + return 1; + } + + /* Ensure that the domain exists, and that it is stopped. */ + if ( xc_domain_pause(xc_handle, domid) ){ + xcio_perror(ioctxt, "Could not pause domain"); + goto out; + } + + if ( xc_domain_getfullinfo( xc_handle, domid, &op, &ctxt) ) + { + xcio_error(ioctxt, "Could not get full domain info"); + goto out; + } + memcpy(name, op.u.getdomaininfo.name, sizeof(name)); + shared_info_frame = op.u.getdomaininfo.shared_info_frame; + + /* A cheesy test to see whether the domain contains valid state. */ + if ( ctxt.pt_base == 0 ){ + xcio_error(ioctxt, "Domain is not in a valid Linux guest OS state"); + goto out; + } + + /* Map the suspend-record MFN to pin it. The page must be owned by + domid for this to succeed. */ + p_srec = mfn_mapper_map_single(xc_handle, domid, + sizeof(*p_srec), PROT_READ, + ctxt.cpu_ctxt.esi); + if (!p_srec){ + xcio_error(ioctxt, "Couldn't map state record"); + goto out; + } + + nr_pfns = p_srec->nr_pfns; + + /* cheesy sanity check */ + if ( nr_pfns > 1024*1024 ){ + xcio_error(ioctxt, "Invalid state record -- pfn count out of range: %lu", nr_pfns); + goto out; + } + + /* the pfn_to_mfn_frame_list fits in a single page */ + live_pfn_to_mfn_frame_list = + mfn_mapper_map_single(xc_handle, domid, + PAGE_SIZE, PROT_READ, + p_srec->pfn_to_mfn_frame_list ); + + if (!live_pfn_to_mfn_frame_list){ + xcio_error(ioctxt, "Couldn't map pfn_to_mfn_frame_list"); + goto out; + } + + /* Track the mfn_to_pfn table down from the domains PT */ + { + unsigned long *pgd; + unsigned long mfn_to_pfn_table_start_mfn; + + pgd = mfn_mapper_map_single(xc_handle, domid, + PAGE_SIZE, PROT_READ, + ctxt.pt_base>>PAGE_SHIFT); + + mfn_to_pfn_table_start_mfn = + pgd[HYPERVISOR_VIRT_START>>L2_PAGETABLE_SHIFT]>>PAGE_SHIFT; + + live_mfn_to_pfn_table = + mfn_mapper_map_single(xc_handle, ~0UL, + PAGE_SIZE*1024, PROT_READ, + mfn_to_pfn_table_start_mfn ); + } + + /* Map all the frames of the pfn->mfn table. For migrate to succeed, + the guest must not change which frames are used for this purpose. + (its not clear why it would want to change them, and we'll be OK + from a safety POV anyhow. */ + + live_pfn_to_mfn_table = mfn_mapper_map_batch(xc_handle, domid, + PROT_READ, + live_pfn_to_mfn_frame_list, + (nr_pfns+1023)/1024 ); + if( !live_pfn_to_mfn_table ){ + xcio_perror(ioctxt, "Couldn't map pfn_to_mfn table"); + goto out; + } + + + /* Canonicalise the pfn-to-mfn table frame-number list. */ + memcpy( pfn_to_mfn_frame_list, live_pfn_to_mfn_frame_list, PAGE_SIZE ); + for ( i = 0; i < nr_pfns; i += 1024 ){ + if ( !translate_mfn_to_pfn(&pfn_to_mfn_frame_list[i/1024]) ){ + xcio_error(ioctxt, "Frame # in pfn-to-mfn frame list is not in pseudophys"); + goto out; + } + } + + /* At this point, we can start the domain again if we're doing a + live suspend */ + + if( live ){ + if ( xc_shadow_control( xc_handle, domid, + DOM0_SHADOW_CONTROL_OP_ENABLE_LOGDIRTY, + NULL, 0, NULL ) < 0 ) { + xcio_error(ioctxt, "Couldn't enable shadow mode"); + goto out; + } + + if ( xc_domain_unpause(xc_handle, domid) < 0 ){ + xcio_error(ioctxt, "Couldn't unpause domain"); + goto out; + } + + last_iter = 0; + sent_last_iter = 1<<20; /* 4GB of pages */ + } else{ + last_iter = 1; + } + + /* calculate the power of 2 order of nr_pfns, e.g. + 15->4 16->4 17->5 */ + for( i=nr_pfns-1, order_nr=0; i ; i>>=1, order_nr++ ); + + /* Setup to_send bitmap */ + { + int sz = (nr_pfns/8) + 8; /* includes slop at end of array */ + + to_send = malloc( sz ); + to_fix = calloc( 1, sz ); + to_skip = malloc( sz ); + + if (!to_send || !to_fix || !to_skip){ + xcio_error(ioctxt, "Couldn't allocate to_send array"); + goto out; + } + + memset( to_send, 0xff, sz ); + + if ( mlock( to_send, sz ) ){ + xcio_perror(ioctxt, "Unable to mlock to_send"); + return 1; + } + + /* (to fix is local only) */ + + if ( mlock( to_skip, sz ) ){ + xcio_perror(ioctxt, "Unable to mlock to_skip"); + return 1; + } + + } + + analysis_phase( xc_handle, domid, nr_pfns, to_skip ); + + /* We want zeroed memory so use calloc rather than malloc. */ + pfn_type = calloc(BATCH_SIZE, sizeof(unsigned long)); + pfn_batch = calloc(BATCH_SIZE, sizeof(unsigned long)); + + if ( (pfn_type == NULL) || (pfn_batch == NULL) ){ + errno = ENOMEM; + goto out; + } + + if ( mlock( pfn_type, BATCH_SIZE * sizeof(unsigned long) ) ){ + xcio_error(ioctxt, "Unable to mlock"); + goto out; + } + + + /* + * Quick belt and braces sanity check. + */ +#if DEBUG + for ( i = 0; i < nr_pfns; i++ ){ + mfn = live_pfn_to_mfn_table[i]; + + if( (live_mfn_to_pfn_table[mfn] != i) && (mfn != 0x80000004) ) + printf("i=0x%x mfn=%x live_mfn_to_pfn_table=%x\n", + i,mfn,live_mfn_to_pfn_table[mfn]); + } +#endif + + /* Map the shared info frame */ + live_shinfo = mfn_mapper_map_single(xc_handle, domid, + PAGE_SIZE, PROT_READ, + shared_info_frame); + + if (!live_shinfo){ + xcio_error(ioctxt, "Couldn't map live_shinfo"); + goto out; + } + + /* Start writing out the saved-domain record. */ + + if ( xcio_write(ioctxt, "LinuxGuestRecord", 16) || + xcio_write(ioctxt, name, sizeof(name)) || + xcio_write(ioctxt, &nr_pfns, sizeof(unsigned long)) || + xcio_write(ioctxt, pfn_to_mfn_frame_list, PAGE_SIZE) ){ + xcio_error(ioctxt, "Error writing header"); + goto out; + } + if(write_vmconfig(ioctxt)){ + xcio_error(ioctxt, "Error writing vmconfig"); + goto out; + } + + print_stats( xc_handle, domid, 0, &stats, 0 ); + + /* Now write out each data page, canonicalising page tables as we go... */ + + while(1){ + unsigned int prev_pc, sent_this_iter, N, batch; + + iter++; + sent_this_iter = 0; + skip_this_iter = 0; + prev_pc = 0; + N=0; + + xcio_info(ioctxt, "Saving memory pages: iter %d 0%%", iter); + + while( N < nr_pfns ){ + unsigned int this_pc = (N * 100) / nr_pfns; + + if ( (this_pc - prev_pc) >= 5 ){ + xcio_info(ioctxt, "\b\b\b\b%3d%%", this_pc); + prev_pc = this_pc; + } + + /* slightly wasteful to peek the whole array evey time, + but this is fast enough for the moment. */ + + if ( !last_iter && + xc_shadow_control(xc_handle, domid, + DOM0_SHADOW_CONTROL_OP_PEEK, + to_skip, nr_pfns, NULL) != nr_pfns ) { + xcio_error(ioctxt, "Error peeking shadow bitmap"); + goto out; + } + + + /* load pfn_type[] with the mfn of all the pages we're doing in + this batch. */ + + for ( batch = 0; batch < BATCH_SIZE && N < nr_pfns ; N++ ) + { + int n = permute(N, nr_pfns, order_nr ); + + if ( 0 && debug ) { + fprintf(stderr,"%d pfn= %08lx mfn= %08lx %d " + " [mfn]= %08lx\n", + iter, (unsigned long)n, live_pfn_to_mfn_table[n], + test_bit(n,to_send), + live_mfn_to_pfn_table[live_pfn_to_mfn_table[n]& + 0xFFFFF]); + } + + if ( !last_iter && + test_bit(n, to_send) && + test_bit(n, to_skip) ) { + skip_this_iter++; /* stats keeping */ + } + + if ( !((test_bit(n, to_send) && !test_bit(n, to_skip)) || + (test_bit(n, to_send) && last_iter) || + (test_bit(n, to_fix) && last_iter)) ) { + continue; + } + + /* we get here if: + 1. page is marked to_send & hasn't already been re-dirtied + 2. (ignore to_skip in last iteration) + 3. add in pages that still need fixup (net bufs) + */ + + pfn_batch[batch] = n; + pfn_type[batch] = live_pfn_to_mfn_table[n]; + + if( pfn_type[batch] == 0x80000004 ){ + /* not currently in pusedo-physical map -- set bit + in to_fix that we must send this page in last_iter + unless its sent sooner anyhow */ + + set_bit( n, to_fix ); + if( iter>1 ) + DDPRINTF("netbuf race: iter %d, pfn %lx. mfn %lx\n", + iter,n,pfn_type[batch]); + continue; + } + + if ( last_iter && + test_bit(n, to_fix) && + !test_bit(n, to_send) ) + { + needed_to_fix++; + DPRINTF("Fix! iter %d, pfn %lx. mfn %lx\n", + iter,n,pfn_type[batch]); + } + + clear_bit(n, to_fix); + + batch++; + } + + DDPRINTF("batch %d:%d (n=%d)\n", iter, batch, n); + + if ( batch == 0 ) + goto skip; /* vanishingly unlikely... */ + + if ( (region_base = mfn_mapper_map_batch(xc_handle, domid, + PROT_READ, + pfn_type, + batch)) == 0 ){ + xcio_perror(ioctxt, "map batch failed"); + goto out; + } + + if ( get_pfn_type_batch(xc_handle, domid, batch, pfn_type) ){ + xcio_error(ioctxt, "get_pfn_type_batch failed"); + goto out; + } + + for ( j = 0; j < batch; j++ ){ + if ( (pfn_type[j] & LTAB_MASK) == XTAB ){ + DDPRINTF("type fail: page %i mfn %08lx\n",j,pfn_type[j]); + continue; + } + + if ( 0 && debug ) + fprintf(stderr, "%d pfn= %08lx mfn= %08lx [mfn]= %08lx" + " sum= %08lx\n", + iter, + (pfn_type[j] & LTAB_MASK) | pfn_batch[j], + pfn_type[j], + live_mfn_to_pfn_table[pfn_type[j]&(~LTAB_MASK)], + csum_page(region_base + (PAGE_SIZE*j))); + + /* canonicalise mfn->pfn */ + pfn_type[j] = (pfn_type[j] & LTAB_MASK) | pfn_batch[j]; + } + + if ( xcio_write(ioctxt, &batch, sizeof(int) ) ){ + xcio_error(ioctxt, "Error when writing to state file (2)"); + goto out; + } + + if ( xcio_write(ioctxt, pfn_type, sizeof(unsigned long)*j ) ){ + xcio_error(ioctxt, "Error when writing to state file (3)"); + goto out; + } + + /* entering this loop, pfn_type is now in pfns (Not mfns) */ + for( j = 0; j < batch; j++ ){ + /* write out pages in batch */ + if( (pfn_type[j] & LTAB_MASK) == XTAB){ + DDPRINTF("SKIP BOGUS page %i mfn %08lx\n",j,pfn_type[j]); + continue; + } + + if ( ((pfn_type[j] & LTAB_MASK) == L1TAB) || + ((pfn_type[j] & LTAB_MASK) == L2TAB) ){ + memcpy(page, region_base + (PAGE_SIZE*j), PAGE_SIZE); + + for ( k = 0; + k < (((pfn_type[j] & LTAB_MASK) == L2TAB) ? + (HYPERVISOR_VIRT_START >> L2_PAGETABLE_SHIFT) : + 1024); + k++ ){ + unsigned long pfn; + + if ( !(page[k] & _PAGE_PRESENT) ) + continue; + + mfn = page[k] >> PAGE_SHIFT; + pfn = live_mfn_to_pfn_table[mfn]; + + if ( !MFN_IS_IN_PSEUDOPHYS_MAP(mfn) ) + { + /* I don't think this should ever happen */ + printf("FNI %d : [%08lx,%d] pte=%08lx, " + "mfn=%08lx, pfn=%08lx [mfn]=%08lx\n", + j, pfn_type[j], k, + page[k], mfn, live_mfn_to_pfn_table[mfn], + (live_mfn_to_pfn_table[mfn]>28, + j,i,mfn,k,page[k],page[k]>>PAGE_SHIFT); +#endif + + } /* end of page table rewrite for loop */ + + if ( xcio_write(ioctxt, page, PAGE_SIZE) ){ + xcio_error(ioctxt, "Error when writing to state file (4)"); + goto out; + } + + } /* end of it's a PT page */ else { /* normal page */ + + if ( xcio_write(ioctxt, region_base + (PAGE_SIZE*j), + PAGE_SIZE) ){ + xcio_error(ioctxt, "Error when writing to state file (5)"); + goto out; + } + } + } /* end of the write out for this batch */ + + sent_this_iter += batch; + + } /* end of this while loop for this iteration */ + + munmap(region_base, batch*PAGE_SIZE); + + skip: + + total_sent += sent_this_iter; + + xcio_info(ioctxt, "\r %d: sent %d, skipped %d, ", + iter, sent_this_iter, skip_this_iter ); + + if ( last_iter ) { + print_stats( xc_handle, domid, sent_this_iter, &stats, 1); + + xcio_info(ioctxt, "Total pages sent= %d (%.2fx)\n", + total_sent, ((float)total_sent)/nr_pfns ); + xcio_info(ioctxt, "(of which %d were fixups)\n", needed_to_fix ); + } + + if (last_iter && debug){ + int minusone = -1; + memset( to_send, 0xff, (nr_pfns+8)/8 ); + debug = 0; + printf("Entering debug resend-all mode\n"); + + /* send "-1" to put receiver into debug mode */ + if ( xcio_write(ioctxt, &minusone, sizeof(int)) ) + { + xcio_error(ioctxt, "Error when writing to state file (6)"); + goto out; + } + + continue; + } + + if ( last_iter ) break; + + if ( live ) + { + if ( + /* ( sent_this_iter > (sent_last_iter * 0.95) ) || */ + (iter >= max_iters) || + (sent_this_iter+skip_this_iter < 50) || + (total_sent > nr_pfns*max_factor) ) + { + DPRINTF("Start last iteration\n"); + last_iter = 1; + + xc_domain_pause( xc_handle, domid ); + } + + if ( xc_shadow_control( xc_handle, domid, + DOM0_SHADOW_CONTROL_OP_CLEAN2, + to_send, nr_pfns, &stats ) != nr_pfns ) + { + xcio_error(ioctxt, "Error flushing shadow PT"); + goto out; + } + + sent_last_iter = sent_this_iter; + + print_stats( xc_handle, domid, sent_this_iter, &stats, 1); + + } + + + } /* end of while 1 */ + + DPRINTF("All memory is saved\n"); + + /* Success! */ + rc = 0; + + /* Zero terminate */ + if ( xcio_write(ioctxt, &rc, sizeof(int)) ) + { + xcio_error(ioctxt, "Error when writing to state file (6)"); + goto out; + } + + /* Get the final execution context */ + if ( xc_domain_getfullinfo( xc_handle, domid, &op, &ctxt) ) + { + xcio_perror(ioctxt, "Could not get full domain info"); + goto out; + } + + /* Canonicalise the suspend-record frame number. */ + if ( !translate_mfn_to_pfn(&ctxt.cpu_ctxt.esi) ){ + xcio_error(ioctxt, "State record is not in range of pseudophys map"); + goto out; + } + + /* Canonicalise each GDT frame number. */ + for ( i = 0; i < ctxt.gdt_ents; i += 512 ) { + if ( !translate_mfn_to_pfn(&ctxt.gdt_frames[i]) ) { + xcio_error(ioctxt, "GDT frame is not in range of pseudophys map"); + goto out; + } + } + + /* Canonicalise the page table base pointer. */ + if ( !MFN_IS_IN_PSEUDOPHYS_MAP(ctxt.pt_base >> PAGE_SHIFT) ) { + xcio_error(ioctxt, "PT base is not in range of pseudophys map"); + goto out; + } + ctxt.pt_base = live_mfn_to_pfn_table[ctxt.pt_base >> PAGE_SHIFT] << + PAGE_SHIFT; + + if ( xcio_write(ioctxt, &ctxt, sizeof(ctxt)) || + xcio_write(ioctxt, live_shinfo, PAGE_SIZE) ) { + xcio_error(ioctxt, "Error when writing to state file (1)"); + goto out; + } + munmap(live_shinfo, PAGE_SIZE); + + out: + if ( pfn_type != NULL ) free(pfn_type); + DPRINTF("Save exit rc=%d\n",rc); + return !!rc; + +} diff --git a/tools/libxc/xc_misc.c b/tools/libxc/xc_misc.c new file mode 100644 index 0000000000..0019ffe96b --- /dev/null +++ b/tools/libxc/xc_misc.c @@ -0,0 +1,87 @@ +/****************************************************************************** + * xc_misc.c + * + * Miscellaneous control interface functions. + */ + +#include "xc_private.h" + +int xc_interface_open(void) +{ + int fd = open("/proc/xen/privcmd", O_RDWR); + if ( fd == -1 ) + PERROR("Could not obtain handle on privileged command interface"); + return fd; +} + +int xc_interface_close(int xc_handle) +{ + return close(xc_handle); +} + + +#define CONSOLE_RING_CLEAR 1 + +int xc_readconsolering(int xc_handle, + char *str, + unsigned int max_chars, + int clear) +{ + int ret; + dom0_op_t op; + + op.cmd = DOM0_READCONSOLE; + op.u.readconsole.str = (unsigned long)str; + op.u.readconsole.count = max_chars; + op.u.readconsole.cmd = clear ? CONSOLE_RING_CLEAR : 0; + + if ( (ret = mlock(str, max_chars)) != 0 ) + return ret; + + if ( (ret = do_dom0_op(xc_handle, &op)) >= 0 ) + str[ret] = '\0'; + + (void)munlock(str, max_chars); + + return ret; +} + + +int xc_physinfo(int xc_handle, + xc_physinfo_t *put_info) +{ + int ret; + dom0_op_t op; + dom0_physinfo_t *got_info = &op.u.physinfo; + + op.cmd = DOM0_PHYSINFO; + op.interface_version = DOM0_INTERFACE_VERSION; + + if((ret = do_dom0_op(xc_handle, &op))) return ret; + + put_info->ht_per_core = got_info->ht_per_core; + put_info->cores = got_info->cores; + put_info->total_pages = got_info->total_pages; + put_info->free_pages = got_info->free_pages; + put_info->cpu_khz = got_info->cpu_khz; + + return 0; +} + + +int xc_sched_id(int xc_handle, + int *sched_id) +{ + int ret; + dom0_op_t op; + + op.cmd = DOM0_SCHED_ID; + op.interface_version = DOM0_INTERFACE_VERSION; + + if((ret = do_dom0_op(xc_handle, &op))) return ret; + + *sched_id = op.u.sched_id.sched_id; + + return 0; +} + diff --git a/tools/libxc/xc_netbsd_build.c b/tools/libxc/xc_netbsd_build.c new file mode 100644 index 0000000000..04a47b5068 --- /dev/null +++ b/tools/libxc/xc_netbsd_build.c @@ -0,0 +1,705 @@ +/****************************************************************************** + * xc_netbsd_build.c + */ + +#include "xc_private.h" +#define ELFSIZE 32 /* XXX */ +#include "xc_elf.h" +#include + +#ifdef DEBUG +#define DPRINTF(x) printf x +#else +#define DPRINTF(x) +#endif + +static int loadelfimage(gzFile, int, unsigned long *, unsigned long, + unsigned long *, unsigned long *, + unsigned long *, unsigned long *); + +#define ELFROUND (ELFSIZE / 8) + +#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED) +#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER) + +static long get_tot_pages(int xc_handle, u32 domid) +{ + dom0_op_t op; + op.cmd = DOM0_GETDOMAININFO; + op.u.getdomaininfo.domain = (domid_t)domid; + op.u.getdomaininfo.ctxt = NULL; + return (do_dom0_op(xc_handle, &op) < 0) ? + -1 : op.u.getdomaininfo.tot_pages; +} + +static int get_pfn_list(int xc_handle, + u32 domid, + unsigned long *pfn_buf, + unsigned long max_pfns) +{ + dom0_op_t op; + int ret; + op.cmd = DOM0_GETMEMLIST; + op.u.getmemlist.domain = (domid_t)domid; + op.u.getmemlist.max_pfns = max_pfns; + op.u.getmemlist.buffer = pfn_buf; + + if ( mlock(pfn_buf, max_pfns * sizeof(unsigned long)) != 0 ) + return -1; + + ret = do_dom0_op(xc_handle, &op); + + (void)munlock(pfn_buf, max_pfns * sizeof(unsigned long)); + + return (ret < 0) ? -1 : op.u.getmemlist.num_pfns; +} + +static int setup_guestos(int xc_handle, + u32 dom, + gzFile kernel_gfd, + unsigned long tot_pages, + unsigned long *virt_startinfo_addr, + unsigned long *virt_load_addr, + full_execution_context_t *ctxt, + const char *cmdline, + unsigned long shared_info_frame, + unsigned int control_evtchn) +{ + l1_pgentry_t *vl1tab=NULL, *vl1e=NULL; + l2_pgentry_t *vl2tab=NULL, *vl2e=NULL; + unsigned long *page_array = NULL; + int alloc_index, num_pt_pages; + unsigned long l2tab; + unsigned long l1tab; + unsigned long count, pt_start; + unsigned long symtab_addr = 0, symtab_len = 0; + extended_start_info_t *start_info; + shared_info_t *shared_info; + unsigned long ksize; + mmu_t *mmu = NULL; + int pm_handle, i; + + if ( (pm_handle = init_pfn_mapper((domid_t)dom)) < 0 ) + goto error_out; + + if ( (page_array = malloc(tot_pages * sizeof(unsigned long))) == NULL ) + { + PERROR("Could not allocate memory"); + goto error_out; + } + + if ( get_pfn_list(xc_handle, dom, page_array, tot_pages) != tot_pages ) + { + PERROR("Could not get the page frame list"); + goto error_out; + } + + if (loadelfimage(kernel_gfd, pm_handle, page_array, tot_pages, + virt_load_addr, &ksize, &symtab_addr, &symtab_len)) + goto error_out; + + /* ksize is kernel-image size rounded up to a page boundary. */ + + alloc_index = tot_pages - 1; + + /* Count bottom-level PTs, rounding up. */ + num_pt_pages = (l1_table_offset(*virt_load_addr) + tot_pages + 1023) + / 1024; + + /* We must also count the page directory. */ + num_pt_pages++; + + /* Index of first PT page. */ + pt_start = tot_pages - num_pt_pages; + + /* + * First allocate page for page dir. Allocation goes backwards from the end + * of the allocated physical address space. + */ + l2tab = page_array[alloc_index] << PAGE_SHIFT; + alloc_index--; + ctxt->pt_base = l2tab; + + if ( (mmu = init_mmu_updates(xc_handle, dom)) == NULL ) + goto error_out; + + /* Initialise the page tables. */ + if ( (vl2tab = map_pfn_writeable(pm_handle, l2tab >> PAGE_SHIFT)) == NULL ) + goto error_out; + memset(vl2tab, 0, PAGE_SIZE); + vl2e = &vl2tab[l2_table_offset(*virt_load_addr)]; + for ( count = 0; count < tot_pages; count++ ) + { + if ( ((unsigned long)vl1e & (PAGE_SIZE-1)) == 0 ) + { + l1tab = page_array[alloc_index--] << PAGE_SHIFT; + if ( vl1tab != NULL ) + unmap_pfn(pm_handle, vl1tab); + if ( (vl1tab = map_pfn_writeable(pm_handle, + l1tab >> PAGE_SHIFT)) == NULL ) + goto error_out; + memset(vl1tab, 0, PAGE_SIZE); + vl1e = &vl1tab[l1_table_offset(*virt_load_addr + + (count<= pt_start ) + *vl1e &= ~_PAGE_RW; + vl1e++; + + if ( add_mmu_update(xc_handle, mmu, + (page_array[count] << PAGE_SHIFT) | + MMU_MACHPHYS_UPDATE, count) ) + goto error_out; + } + unmap_pfn(pm_handle, vl1tab); + unmap_pfn(pm_handle, vl2tab); + + /* + * Pin down l2tab addr as page dir page - causes hypervisor to provide + * correct protection for the page + */ + if ( add_mmu_update(xc_handle, mmu, + l2tab | MMU_EXTENDED_COMMAND, MMUEXT_PIN_L2_TABLE) ) + goto error_out; + + *virt_startinfo_addr = + *virt_load_addr + ((alloc_index-1) << PAGE_SHIFT); + + start_info = map_pfn_writeable(pm_handle, page_array[alloc_index-1]); + memset(start_info, 0, sizeof(*start_info)); + start_info->pt_base = *virt_load_addr + ((tot_pages-1) << PAGE_SHIFT); + start_info->mod_start = symtab_addr; + start_info->mod_len = symtab_len; + start_info->nr_pages = tot_pages; + start_info->shared_info = shared_info_frame << PAGE_SHIFT; + start_info->flags = 0; + start_info->domain_controller_evtchn = control_evtchn; + strncpy(start_info->cmd_line, cmdline, MAX_CMDLINE); + start_info->cmd_line[MAX_CMDLINE-1] = '\0'; + unmap_pfn(pm_handle, start_info); + + /* shared_info page starts its life empty. */ + shared_info = map_pfn_writeable(pm_handle, shared_info_frame); + memset(shared_info, 0, PAGE_SIZE); + /* Mask all upcalls... */ + for ( i = 0; i < MAX_VIRT_CPUS; i++ ) + shared_info->vcpu_data[i].evtchn_upcall_mask = 1; + unmap_pfn(pm_handle, shared_info); + + /* Send the page update requests down to the hypervisor. */ + if ( finish_mmu_updates(xc_handle, mmu) ) + goto error_out; + + free(mmu); + (void)close_pfn_mapper(pm_handle); + free(page_array); + return 0; + + error_out: + if ( mmu != NULL ) + free(mmu); + if ( pm_handle >= 0 ) + (void)close_pfn_mapper(pm_handle); + if ( page_array == NULL ) + free(page_array); + return -1; +} + +int xc_netbsd_build(int xc_handle, + u32 domid, + const char *image_name, + const char *cmdline, + unsigned int control_evtchn) +{ + dom0_op_t launch_op, op; + unsigned long load_addr; + long tot_pages; + int kernel_fd = -1; + gzFile kernel_gfd = NULL; + int rc, i; + full_execution_context_t st_ctxt, *ctxt = &st_ctxt; + unsigned long virt_startinfo_addr; + + if ( (tot_pages = get_tot_pages(xc_handle, domid)) < 0 ) + { + PERROR("Could not find total pages for domain"); + return 1; + } + + kernel_fd = open(image_name, O_RDONLY); + if ( kernel_fd < 0 ) + { + PERROR("Could not open kernel image"); + return 1; + } + + if ( (kernel_gfd = gzdopen(kernel_fd, "rb")) == NULL ) + { + PERROR("Could not allocate decompression state for state file"); + close(kernel_fd); + return 1; + } + + if ( mlock(&st_ctxt, sizeof(st_ctxt) ) ) + { + PERROR("Unable to mlock ctxt"); + return 1; + } + + op.cmd = DOM0_GETDOMAININFO; + op.u.getdomaininfo.domain = (domid_t)domid; + op.u.getdomaininfo.ctxt = ctxt; + if ( (do_dom0_op(xc_handle, &op) < 0) || + ((u32)op.u.getdomaininfo.domain != domid) ) + { + PERROR("Could not get info on domain"); + goto error_out; + } + if ( !(op.u.getdomaininfo.flags & DOMFLAGS_PAUSED) || + (op.u.getdomaininfo.ctxt->pt_base != 0) ) + { + ERROR("Domain is already constructed"); + goto error_out; + } + + if ( setup_guestos(xc_handle, domid, kernel_gfd, tot_pages, + &virt_startinfo_addr, + &load_addr, &st_ctxt, cmdline, + op.u.getdomaininfo.shared_info_frame, + control_evtchn) < 0 ) + { + ERROR("Error constructing guest OS"); + goto error_out; + } + + if ( kernel_fd >= 0 ) + close(kernel_fd); + if( kernel_gfd ) + gzclose(kernel_gfd); + + ctxt->flags = 0; + + /* + * Initial register values: + * DS,ES,FS,GS = FLAT_GUESTOS_DS + * CS:EIP = FLAT_GUESTOS_CS:start_pc + * SS:ESP = FLAT_GUESTOS_DS:start_stack + * ESI = start_info + * [EAX,EBX,ECX,EDX,EDI,EBP are zero] + * EFLAGS = IF | 2 (bit 1 is reserved and should always be 1) + */ + ctxt->cpu_ctxt.ds = FLAT_GUESTOS_DS; + ctxt->cpu_ctxt.es = FLAT_GUESTOS_DS; + ctxt->cpu_ctxt.fs = FLAT_GUESTOS_DS; + ctxt->cpu_ctxt.gs = FLAT_GUESTOS_DS; + ctxt->cpu_ctxt.ss = FLAT_GUESTOS_DS; + ctxt->cpu_ctxt.cs = FLAT_GUESTOS_CS; + ctxt->cpu_ctxt.eip = load_addr; + ctxt->cpu_ctxt.esp = virt_startinfo_addr; + ctxt->cpu_ctxt.esi = virt_startinfo_addr; + ctxt->cpu_ctxt.eflags = (1<<9) | (1<<2); + + /* FPU is set up to default initial state. */ + memset(ctxt->fpu_ctxt, 0, sizeof(ctxt->fpu_ctxt)); + + /* Virtual IDT is empty at start-of-day. */ + for ( i = 0; i < 256; i++ ) + { + ctxt->trap_ctxt[i].vector = i; + ctxt->trap_ctxt[i].cs = FLAT_GUESTOS_CS; + } + ctxt->fast_trap_idx = 0; + + /* No LDT. */ + ctxt->ldt_ents = 0; + + /* Use the default Xen-provided GDT. */ + ctxt->gdt_ents = 0; + + /* Ring 1 stack is the initial stack. */ + ctxt->guestos_ss = FLAT_GUESTOS_DS; + ctxt->guestos_esp = virt_startinfo_addr; + + /* No debugging. */ + memset(ctxt->debugreg, 0, sizeof(ctxt->debugreg)); + + /* No callback handlers. */ + ctxt->event_callback_cs = FLAT_GUESTOS_CS; + ctxt->event_callback_eip = 0; + ctxt->failsafe_callback_cs = FLAT_GUESTOS_CS; + ctxt->failsafe_callback_eip = 0; + + memset( &launch_op, 0, sizeof(launch_op) ); + + launch_op.u.builddomain.domain = (domid_t)domid; + launch_op.u.builddomain.ctxt = ctxt; + launch_op.cmd = DOM0_BUILDDOMAIN; + rc = do_dom0_op(xc_handle, &launch_op); + + return rc; + + error_out: + if ( kernel_fd >= 0 ) + close(kernel_fd); + if( kernel_gfd ) + gzclose(kernel_gfd); + + return -1; +} + +#define MYSEEK_BUFSIZE 1024 +static off_t +myseek(gzFile gfd, off_t offset, int whence) +{ + unsigned char tmp[MYSEEK_BUFSIZE]; + int c; + + if ( offset < 0 ) + { + ERROR("seek back not supported"); + return -1; + } + + while ( offset != 0 ) + { + c = offset; + if ( c > MYSEEK_BUFSIZE ) + c = MYSEEK_BUFSIZE; + if ( gzread(gfd, tmp, c) != c ) + { + PERROR("Error seeking in image."); + return -1; + } + offset -= c; + } + + return 0; /* XXX */ +} + +/* + * NetBSD memory layout: + * + * ---------------- *virt_load_addr = ehdr.e_entry (0xc0100000) + * | kernel text | + * | | + * ---------------- + * | kernel data | + * | | + * ---------------- + * | kernel bss | + * | | + * ---------------- *symtab_addr + * | symtab size | = *symtab_len + * ---------------- + * | elf header | offsets to symbol sections mangled to be relative + * | | to headers location + * ---------------- + * | sym section | + * | headers | + * ---------------- + * | sym sections | + * | | + * ---------------- *symtab_addr + *symtab_len + * | padding | + * ---------------- ehdr.e_entry + *ksize << PAGE_SHIFT + */ + +#define IS_TEXT(p) (p.p_flags & PF_X) +#define IS_DATA(p) (p.p_flags & PF_W) +#define IS_BSS(p) (p.p_filesz < p.p_memsz) + +static int +loadelfimage(gzFile kernel_gfd, int pm_handle, unsigned long *page_array, + unsigned long tot_pages, unsigned long *virt_load_addr, + unsigned long *ksize, unsigned long *symtab_addr, + unsigned long *symtab_len) +{ + Elf_Ehdr ehdr; + Elf_Phdr *phdr; + Elf_Shdr *shdr; + void *vaddr; + char page[PAGE_SIZE], *p; + unsigned long iva, maxva, symva; + int c, curpos, h, i, ret, s; + + ret = -1; + phdr = NULL; + p = NULL; + maxva = 0; + + if ( gzread(kernel_gfd, &ehdr, sizeof(Elf_Ehdr)) != sizeof(Elf_Ehdr) ) + { + PERROR("Error reading kernel image ELF header."); + goto out; + } + curpos = sizeof(Elf_Ehdr); + + if ( !IS_ELF(ehdr) ) + { + PERROR("Image does not have an ELF header."); + goto out; + } + + *virt_load_addr = ehdr.e_entry; + + if ( (*virt_load_addr & (PAGE_SIZE-1)) != 0 ) + { + ERROR("We can only deal with page-aligned load addresses"); + goto out; + } + + if ( (*virt_load_addr + (tot_pages << PAGE_SHIFT)) > + HYPERVISOR_VIRT_START ) + { + ERROR("Cannot map all domain memory without hitting Xen space"); + goto out; + } + + + phdr = malloc(ehdr.e_phnum * sizeof(Elf_Phdr)); + if ( phdr == NULL ) + { + ERROR("Cannot allocate memory for Elf_Phdrs"); + goto out; + } + + if ( myseek(kernel_gfd, ehdr.e_phoff - curpos, SEEK_SET) == -1 ) + { + ERROR("Seek to program header failed"); + goto out; + } + curpos = ehdr.e_phoff; + + if ( gzread(kernel_gfd, phdr, ehdr.e_phnum * sizeof(Elf_Phdr)) != + ehdr.e_phnum * sizeof(Elf_Phdr) ) + { + PERROR("Error reading kernel image ELF program header."); + goto out; + } + curpos += ehdr.e_phnum * sizeof(Elf_Phdr); + + /* Copy run-time 'load' segments that are writeable and/or executable. */ + for ( h = 0; h < ehdr.e_phnum; h++ ) + { + if ( (phdr[h].p_type != PT_LOAD) || + ((phdr[h].p_flags & (PF_W|PF_X)) == 0) ) + continue; + + if ( IS_TEXT(phdr[h]) || IS_DATA(phdr[h]) ) + { + if ( myseek(kernel_gfd, phdr[h].p_offset - curpos, + SEEK_SET) == -1 ) + { + ERROR("Seek to section failed"); + goto out; + } + curpos = phdr[h].p_offset; + + for ( iva = phdr[h].p_vaddr; + iva < phdr[h].p_vaddr + phdr[h].p_filesz; + iva += c) + { + c = PAGE_SIZE - (iva & (PAGE_SIZE - 1)); + if (iva + c > phdr[h].p_vaddr + phdr[h].p_filesz) + c = phdr[h].p_vaddr + phdr[h].p_filesz - iva; + if ( gzread(kernel_gfd, page, c) != c ) + { + PERROR("Error reading kernel image page."); + goto out; + } + curpos += c; + vaddr = map_pfn_writeable(pm_handle, + page_array[(iva - *virt_load_addr) + >> PAGE_SHIFT]); + if ( vaddr == NULL ) + { + ERROR("Couldn't map guest memory"); + goto out; + } + DPRINTF(("copy page %p to %p, count 0x%x\n", (void *)iva, + vaddr + (iva & (PAGE_SIZE - 1)), c)); + memcpy(vaddr + (iva & (PAGE_SIZE - 1)), page, c); + unmap_pfn(pm_handle, vaddr); + } + + if ( phdr[h].p_vaddr + phdr[h].p_filesz > maxva ) + maxva = phdr[h].p_vaddr + phdr[h].p_filesz; + } + + if ( IS_BSS(phdr[h]) ) + { + /* XXX maybe clear phdr[h].p_memsz bytes from + phdr[h].p_vaddr + phdr[h].p_filesz ??? */ + if (phdr[h].p_vaddr + phdr[h].p_memsz > maxva) + maxva = phdr[h].p_vaddr + phdr[h].p_memsz; + DPRINTF(("bss from %p to %p, maxva %p\n", + (void *)(phdr[h].p_vaddr + phdr[h].p_filesz), + (void *)(phdr[h].p_vaddr + phdr[h].p_memsz), + (void *)maxva)); + } + } + + p = malloc(sizeof(int) + sizeof(Elf_Ehdr) + + ehdr.e_shnum * sizeof(Elf_Shdr)); + if ( p == NULL ) + { + ERROR("Cannot allocate memory for Elf_Shdrs"); + goto out; + } + + shdr = (Elf_Shdr *)(p + sizeof(int) + sizeof(Elf_Ehdr)); + + if ( myseek(kernel_gfd, ehdr.e_shoff - curpos, SEEK_SET) == -1 ) + { + ERROR("Seek to symbol header failed"); + goto out; + } + curpos = ehdr.e_shoff; + + if ( gzread(kernel_gfd, shdr, ehdr.e_shnum * sizeof(Elf_Shdr)) != + ehdr.e_shnum * sizeof(Elf_Shdr) ) + { + PERROR("Error reading kernel image ELF symbol header."); + goto out; + } + curpos += ehdr.e_shnum * sizeof(Elf_Shdr); + + maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1); + symva = maxva; + maxva += sizeof(int); + *symtab_addr = maxva; + *symtab_len = 0; + maxva += sizeof(Elf_Ehdr) + ehdr.e_shnum * sizeof(Elf_Shdr); + maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1); + + /* Copy kernel string / symbol tables into physical memory */ + for ( h = 0; h < ehdr.e_shnum; h++ ) + { + if ( shdr[h].sh_type == SHT_STRTAB ) + { + /* Look for a strtab @i linked to symtab @h. */ + for ( i = 0; i < ehdr.e_shnum; i++ ) + if ( (shdr[i].sh_type == SHT_SYMTAB) && + (shdr[i].sh_link == h) ) + break; + /* Skip symtab @h if we found no corresponding strtab @i. */ + if ( i == ehdr.e_shnum ) + { + shdr[h].sh_offset = 0; + continue; + } + } + + if ( (shdr[h].sh_type == SHT_STRTAB) || + (shdr[h].sh_type == SHT_SYMTAB) ) + { + if ( myseek(kernel_gfd, shdr[h].sh_offset - curpos, + SEEK_SET) == -1 ) + { + ERROR("Seek to symbol section failed"); + goto out; + } + curpos = shdr[h].sh_offset; + + /* Mangled to be based on ELF header location. */ + shdr[h].sh_offset = maxva - *symtab_addr; + + DPRINTF(("copy section %d, size 0x%x\n", h, shdr[h].sh_size)); + for ( i = 0; i < shdr[h].sh_size; i += c, maxva += c ) + { + c = PAGE_SIZE - (maxva & (PAGE_SIZE - 1)); + if ( c > (shdr[h].sh_size - i) ) + c = shdr[h].sh_size - i; + if ( gzread(kernel_gfd, page, c) != c ) + { + PERROR("Error reading kernel image page."); + goto out; + } + curpos += c; + + vaddr = map_pfn_writeable(pm_handle, + page_array[(maxva - *virt_load_addr) + >> PAGE_SHIFT]); + if ( vaddr == NULL ) + { + ERROR("Couldn't map guest memory"); + goto out; + } + DPRINTF(("copy page %p to %p, count 0x%x\n", (void *)maxva, + vaddr + (maxva & (PAGE_SIZE - 1)), c)); + memcpy(vaddr + (maxva & (PAGE_SIZE - 1)), page, c); + unmap_pfn(pm_handle, vaddr); + } + + *symtab_len += shdr[h].sh_size; + maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1); + + } + shdr[h].sh_name = 0; /* Name is NULL. */ + } + + if ( *symtab_len == 0 ) + { + DPRINTF(("no symbol table\n")); + *symtab_addr = 0; + ret = 0; + goto out; + } + + DPRINTF(("sym header va %p from %p/%p size %x/%x\n", (void *)symva, + shdr, p, ehdr.e_shnum * sizeof(Elf_Shdr), + ehdr.e_shnum * sizeof(Elf_Shdr) + sizeof(Elf_Ehdr))); + ehdr.e_phoff = 0; + ehdr.e_shoff = sizeof(Elf_Ehdr); + ehdr.e_phentsize = 0; + ehdr.e_phnum = 0; + ehdr.e_shstrndx = SHN_UNDEF; + memcpy(p + sizeof(int), &ehdr, sizeof(Elf_Ehdr)); + *(int *)p = maxva - *symtab_addr; + + /* Copy total length, crafted ELF header and section header table */ + s = sizeof(int) + sizeof(Elf_Ehdr) + ehdr.e_shnum * sizeof(Elf_Shdr); + for ( i = 0; i < s; i += c, symva += c ) + { + c = PAGE_SIZE - (symva & (PAGE_SIZE - 1)); + if ( c > s - i ) + c = s - i; + vaddr = map_pfn_writeable(pm_handle, + page_array[(symva - *virt_load_addr) + >> PAGE_SHIFT]); + if ( vaddr == NULL ) + { + ERROR("Couldn't map guest memory"); + goto out; + } + DPRINTF(("copy page %p to %p, count 0x%x\n", (void *)symva, + vaddr + (symva & (PAGE_SIZE - 1)), c)); + memcpy(vaddr + (symva & (PAGE_SIZE - 1)), p + i, + c); + unmap_pfn(pm_handle, vaddr); + } + + *symtab_len = maxva - *symtab_addr; + + ret = 0; + + out: + if ( ret == 0 ) + { + maxva = (maxva + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); + *ksize = (maxva - *virt_load_addr) >> PAGE_SHIFT; + + DPRINTF(("virt_addr %p, kpages 0x%lx, symtab_addr %p, symtab_len %p\n", + (void *)*virt_load_addr, *ksize, (void *)*symtab_addr, + (void *)*symtab_len)); + } + + if ( phdr != NULL ) + free(phdr); + if ( p != NULL ) + free(p); + return ret; +} diff --git a/tools/libxc/xc_physdev.c b/tools/libxc/xc_physdev.c new file mode 100644 index 0000000000..ba5dd9ccdc --- /dev/null +++ b/tools/libxc/xc_physdev.c @@ -0,0 +1,29 @@ +/****************************************************************************** + * xc_physdev.c + * + * API for manipulating physical-device access permissions. + * + * Copyright (c) 2004, Rolf Neugebauer (Intel Research Cambridge) + * Copyright (c) 2004, K A Fraser (University of Cambridge) + */ + +#include "xc_private.h" + +int xc_physdev_pci_access_modify(int xc_handle, + u32 domid, + int bus, + int dev, + int func, + int enable) +{ + dom0_op_t op; + + op.cmd = DOM0_PCIDEV_ACCESS; + op.u.pcidev_access.domain = (domid_t)domid; + op.u.pcidev_access.bus = bus; + op.u.pcidev_access.dev = dev; + op.u.pcidev_access.func = func; + op.u.pcidev_access.enable = enable; + + return do_dom0_op(xc_handle, &op); +} diff --git a/tools/libxc/xc_private.c b/tools/libxc/xc_private.c new file mode 100644 index 0000000000..344f48254d --- /dev/null +++ b/tools/libxc/xc_private.c @@ -0,0 +1,230 @@ +/****************************************************************************** + * xc_private.c + * + * Helper functions for the rest of the library. + */ + +#include "xc_private.h" + +int init_pfn_mapper(domid_t domid) +{ + int fd = open("/dev/mem", O_RDWR); + if ( fd >= 0 ) + (void)ioctl(fd, _IO('M', 1), (unsigned long)domid); + return fd; +} + +int close_pfn_mapper(int pm_handle) +{ + return close(pm_handle); +} + +void *map_pfn_writeable(int pm_handle, unsigned long pfn) +{ + void *vaddr = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE, + MAP_SHARED, pm_handle, pfn << PAGE_SHIFT); + if ( vaddr == MAP_FAILED ) + return NULL; + return vaddr; +} + +void *map_pfn_readonly(int pm_handle, unsigned long pfn) +{ + void *vaddr = mmap(NULL, PAGE_SIZE, PROT_READ, + MAP_SHARED, pm_handle, pfn << PAGE_SHIFT); + if ( vaddr == MAP_FAILED ) + return NULL; + return vaddr; +} + +void unmap_pfn(int pm_handle, void *vaddr) +{ + (void)munmap(vaddr, PAGE_SIZE); +} + +/*******************/ + +void * mfn_mapper_map_batch(int xc_handle, domid_t dom, int prot, + unsigned long *arr, int num ) +{ + privcmd_mmapbatch_t ioctlx; + void *addr; + addr = mmap( NULL, num*PAGE_SIZE, prot, MAP_SHARED, xc_handle, 0 ); + if (addr) + { + ioctlx.num=num; + ioctlx.dom=dom; + ioctlx.addr=(unsigned long)addr; + ioctlx.arr=arr; + if ( ioctl( xc_handle, IOCTL_PRIVCMD_MMAPBATCH, &ioctlx ) < 0 ) + { + perror("XXXXXXXX"); + munmap(addr, num*PAGE_SIZE); + return 0; + } + } + return addr; + +} + +/*******************/ + +void * mfn_mapper_map_single(int xc_handle, domid_t dom, + int size, int prot, + unsigned long mfn ) +{ + privcmd_mmap_t ioctlx; + privcmd_mmap_entry_t entry; + void *addr; + addr = mmap( NULL, size, prot, MAP_SHARED, xc_handle, 0 ); + if (addr) + { + ioctlx.num=1; + ioctlx.dom=dom; + ioctlx.entry=&entry; + entry.va=(unsigned long) addr; + entry.mfn=mfn; + entry.npages=(size+PAGE_SIZE-1)>>PAGE_SHIFT; + if ( ioctl( xc_handle, IOCTL_PRIVCMD_MMAP, &ioctlx ) <0 ) + { + munmap(addr, size); + return 0; + } + } + return addr; +} + +/*******************/ + +/* NB: arr must be mlock'ed */ +int get_pfn_type_batch(int xc_handle, + u32 dom, int num, unsigned long *arr) +{ + dom0_op_t op; + op.cmd = DOM0_GETPAGEFRAMEINFO2; + op.u.getpageframeinfo2.domain = (domid_t)dom; + op.u.getpageframeinfo2.num = num; + op.u.getpageframeinfo2.array = arr; + return do_dom0_op(xc_handle, &op); +} + +#define GETPFN_ERR (~0U) +unsigned int get_pfn_type(int xc_handle, + unsigned long mfn, + u32 dom) +{ + dom0_op_t op; + op.cmd = DOM0_GETPAGEFRAMEINFO; + op.u.getpageframeinfo.pfn = mfn; + op.u.getpageframeinfo.domain = (domid_t)dom; + if ( do_dom0_op(xc_handle, &op) < 0 ) + { + PERROR("Unexpected failure when getting page frame info!"); + return GETPFN_ERR; + } + return op.u.getpageframeinfo.type; +} + + + +/*******************/ + +#define FIRST_MMU_UPDATE 1 + +static int flush_mmu_updates(int xc_handle, mmu_t *mmu) +{ + int err = 0; + privcmd_hypercall_t hypercall; + + if ( mmu->idx == FIRST_MMU_UPDATE ) + return 0; + + /* The first two requests set the correct subject domain (PTS and GPS). */ + mmu->updates[0].val = (unsigned long)(mmu->subject<<16) & ~0xFFFFUL; + mmu->updates[0].ptr = (unsigned long)(mmu->subject<< 0) & ~0xFFFFUL; + mmu->updates[0].ptr |= MMU_EXTENDED_COMMAND; + mmu->updates[0].val |= MMUEXT_SET_SUBJECTDOM | SET_PAGETABLE_SUBJECTDOM; + + hypercall.op = __HYPERVISOR_mmu_update; + hypercall.arg[0] = (unsigned long)mmu->updates; + hypercall.arg[1] = (unsigned long)mmu->idx; + hypercall.arg[2] = 0; + + if ( mlock(mmu->updates, sizeof(mmu->updates)) != 0 ) + { + PERROR("Could not lock pagetable update array"); + err = 1; + goto out; + } + + if ( do_xen_hypercall(xc_handle, &hypercall) < 0 ) + { + ERROR("Failure when submitting mmu updates"); + err = 1; + } + + mmu->idx = FIRST_MMU_UPDATE; + + (void)munlock(mmu->updates, sizeof(mmu->updates)); + + out: + return err; +} + +mmu_t *init_mmu_updates(int xc_handle, domid_t dom) +{ + mmu_t *mmu = malloc(sizeof(mmu_t)); + if ( mmu == NULL ) + return mmu; + mmu->idx = FIRST_MMU_UPDATE; + mmu->subject = dom; + return mmu; +} + +int add_mmu_update(int xc_handle, mmu_t *mmu, + unsigned long ptr, unsigned long val) +{ + mmu->updates[mmu->idx].ptr = ptr; + mmu->updates[mmu->idx].val = val; + + if ( ++mmu->idx == MAX_MMU_UPDATES ) + return flush_mmu_updates(xc_handle, mmu); + + return 0; +} + +int finish_mmu_updates(int xc_handle, mmu_t *mmu) +{ + return flush_mmu_updates(xc_handle, mmu); +} + + +long long xc_domain_get_cpu_usage( int xc_handle, domid_t domid ) +{ + dom0_op_t op; + + op.cmd = DOM0_GETDOMAININFO; + op.u.getdomaininfo.domain = (domid_t)domid; + op.u.getdomaininfo.ctxt = NULL; + if ( (do_dom0_op(xc_handle, &op) < 0) || + ((u32)op.u.getdomaininfo.domain != domid) ) + { + PERROR("Could not get info on domain"); + return -1; + } + return op.u.getdomaininfo.cpu_time; +} + + +/* This is shared between save and restore, and may generally be useful. */ +unsigned long csum_page (void * page) +{ + int i; + unsigned long *p = page; + unsigned long long sum=0; + + for ( i = 0; i < (PAGE_SIZE/sizeof(unsigned long)); i++ ) + sum += p[i]; + + return sum ^ (sum>>32); +} diff --git a/tools/libxc/xc_private.h b/tools/libxc/xc_private.h new file mode 100644 index 0000000000..742185161b --- /dev/null +++ b/tools/libxc/xc_private.h @@ -0,0 +1,213 @@ + +#ifndef __XC_PRIVATE_H__ +#define __XC_PRIVATE_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xc.h" + +/* from xen/include/hypervisor-ifs */ +#include +#include +#include +#include + +#include + +/* from xend/lib */ +#include + +#define _PAGE_PRESENT 0x001 +#define _PAGE_RW 0x002 +#define _PAGE_USER 0x004 +#define _PAGE_PWT 0x008 +#define _PAGE_PCD 0x010 +#define _PAGE_ACCESSED 0x020 +#define _PAGE_DIRTY 0x040 +#define _PAGE_PAT 0x080 +#define _PAGE_PSE 0x080 +#define _PAGE_GLOBAL 0x100 + + +#define L1_PAGETABLE_SHIFT 12 +#define L2_PAGETABLE_SHIFT 22 + +#define ENTRIES_PER_L1_PAGETABLE 1024 +#define ENTRIES_PER_L2_PAGETABLE 1024 + +#define PAGE_SHIFT L1_PAGETABLE_SHIFT +#define PAGE_SIZE (1UL << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE-1)) + +typedef unsigned long l1_pgentry_t; +typedef unsigned long l2_pgentry_t; + +#define l1_table_offset(_a) \ + (((_a) >> L1_PAGETABLE_SHIFT) & (ENTRIES_PER_L1_PAGETABLE - 1)) +#define l2_table_offset(_a) \ + ((_a) >> L2_PAGETABLE_SHIFT) + +#define ERROR(_m, _a...) \ + fprintf(stderr, "ERROR: " _m "\n" , ## _a ) + +#define PERROR(_m, _a...) \ + fprintf(stderr, "ERROR: " _m " (%d = %s)\n" , ## _a , \ + errno, strerror(errno)) + +static inline int do_privcmd(int xc_handle, + unsigned int cmd, + unsigned long data) +{ + return ioctl(xc_handle, cmd, data); +} + +static inline int do_xen_hypercall(int xc_handle, + privcmd_hypercall_t *hypercall) +{ + return do_privcmd(xc_handle, + IOCTL_PRIVCMD_HYPERCALL, + (unsigned long)hypercall); +} + +static inline int do_dom0_op(int xc_handle, dom0_op_t *op) +{ + int ret = -1; + privcmd_hypercall_t hypercall; + + op->interface_version = DOM0_INTERFACE_VERSION; + + hypercall.op = __HYPERVISOR_dom0_op; + hypercall.arg[0] = (unsigned long)op; + + if ( mlock(op, sizeof(*op)) != 0 ) + { + PERROR("Could not lock memory for Xen hypercall"); + goto out1; + } + + if ( (ret = do_xen_hypercall(xc_handle, &hypercall)) < 0 ) + { + if ( errno == EACCES ) + fprintf(stderr, "Dom0 operation failed -- need to" + " rebuild the user-space tool set?\n"); + goto out2; + } + + out2: (void)munlock(op, sizeof(*op)); + out1: return ret; +} + +static inline int do_multicall_op(int xc_handle, + void *call_list, int nr_calls) +{ + int ret = -1; + privcmd_hypercall_t hypercall; + + hypercall.op = __HYPERVISOR_multicall; + hypercall.arg[0] = (unsigned long)call_list; + hypercall.arg[1] = (unsigned long)nr_calls; + + if ( (ret = do_xen_hypercall(xc_handle, &hypercall)) < 0 ) + { + if ( errno == EACCES ) + fprintf(stderr, "Dom0 operation failed -- need to" + " rebuild the user-space tool set?\n"); + goto out1; + } + + out1: return ret; +} + +/* + * PFN mapping. + */ +int init_pfn_mapper(domid_t domid); +int close_pfn_mapper(int pm_handle); +void *map_pfn_writeable(int pm_handle, unsigned long pfn); +void *map_pfn_readonly(int pm_handle, unsigned long pfn); +void unmap_pfn(int pm_handle, void *vaddr); +int get_pfn_type_batch(int xc_handle, u32 dom, int num, unsigned long *arr); +unsigned long csum_page (void * page); + +/* + * MMU updates. + */ +#define MAX_MMU_UPDATES 1024 +typedef struct { + mmu_update_t updates[MAX_MMU_UPDATES]; + int idx; + domid_t subject; +} mmu_t; +mmu_t *init_mmu_updates(int xc_handle, domid_t dom); +int add_mmu_update(int xc_handle, mmu_t *mmu, + unsigned long ptr, unsigned long val); +int finish_mmu_updates(int xc_handle, mmu_t *mmu); + + +/* + * ioctl-based mfn mapping interface + */ + +/* +typedef struct privcmd_mmap_entry { + unsigned long va; + unsigned long mfn; + unsigned long npages; +} privcmd_mmap_entry_t; + +typedef struct privcmd_mmap { + int num; + domid_t dom; + privcmd_mmap_entry_t *entry; +} privcmd_mmap_t; +*/ + +#define mfn_mapper_queue_size 128 + +typedef struct mfn_mapper { + int xc_handle; + int size; + int prot; + int error; + int max_queue_size; + void * addr; + privcmd_mmap_t ioctl; + +} mfn_mapper_t; + +void * mfn_mapper_map_single(int xc_handle, domid_t dom, int size, int prot, + unsigned long mfn ); + +void * mfn_mapper_map_batch(int xc_handle, domid_t dom, int prot, + unsigned long *arr, int num ); + +mfn_mapper_t * mfn_mapper_init(int xc_handle, domid_t dom, int size, int prot); + +void * mfn_mapper_base(mfn_mapper_t *t); + +void mfn_mapper_close(mfn_mapper_t *t); + +int mfn_mapper_flush_queue(mfn_mapper_t *t); + +void * mfn_mapper_queue_entry(mfn_mapper_t *t, int offset, + unsigned long mfn, int size ); + +long long xc_domain_get_cpu_usage( int xc_handle, domid_t domid ); + +#include "xc_io.h" + +int xc_domain_getfullinfo(int xc_handle, + u32 domid, + dom0_op_t *op, + full_execution_context_t *ctxt ); +#endif /* __XC_PRIVATE_H__ */ diff --git a/tools/libxc/xc_rrobin.c b/tools/libxc/xc_rrobin.c new file mode 100644 index 0000000000..ad37962f3b --- /dev/null +++ b/tools/libxc/xc_rrobin.c @@ -0,0 +1,37 @@ +/****************************************************************************** + * xc_rrobin.c + * + * API for manipulating parameters of the Round Robin scheduler + * + * by Mark Williamson, Copyright (c) 2004 Intel Research Cambridge. + */ + +#include "xc_private.h" + +int xc_rrobin_global_set(int xc_handle, u64 slice) +{ + dom0_op_t op; + op.cmd = DOM0_SCHEDCTL; + op.u.schedctl.sched_id = SCHED_RROBIN; + op.u.schedctl.direction = SCHED_INFO_PUT; + + op.u.schedctl.u.rrobin.slice = slice; + return do_dom0_op(xc_handle, &op); +} + + +int xc_rrobin_global_get(int xc_handle, u64 *slice) +{ + dom0_op_t op; + int ret; + + op.cmd = DOM0_SCHEDCTL; + op.u.schedctl.sched_id = SCHED_RROBIN; + op.u.schedctl.direction = SCHED_INFO_GET; + + ret = do_dom0_op(xc_handle, &op); + + *slice = op.u.schedctl.u.rrobin.slice; + + return ret; +} diff --git a/tools/libxutil/Makefile b/tools/libxutil/Makefile new file mode 100644 index 0000000000..0e92fa771f --- /dev/null +++ b/tools/libxutil/Makefile @@ -0,0 +1,80 @@ +XEN_ROOT = ../.. +include $(XEN_ROOT)/tools/Make.defs + +CC = gcc + +LIB_SRCS := +LIB_SRCS += allocate.c +#LIB_SRCS += enum.c +LIB_SRCS += file_stream.c +LIB_SRCS += gzip_stream.c +#LIB_SRCS += hash_table.c +LIB_SRCS += iostream.c +#LIB_SRCS += kernel_stream.c +#LIB_SRCS += lexis.c +#LIB_SRCS += lzi_stream.c +#LIB_SRCS += lzo_stream.c +#LIB_SRCS += marshal.c +#LIB_SRCS += socket_stream.c +#LIB_SRCS += string_stream.c +#LIB_SRCS += sxpr.c +#LIB_SRCS += sxpr_parser.c +LIB_SRCS += sys_net.c +LIB_SRCS += sys_string.c +#LIB_SRCS += xdr.c + +LIB_OBJS := $(LIB_SRCS:.c=.o) + +CFLAGS += -Wall +CFLAGS += -Werror +CFLAGS += -g +CFLAGS += -O3 +CFLAGS += -fno-strict-aliasing +#CFLAGS += $(INCLUDES) +# Get gcc to generate the dependencies for us. +CFLAGS += -Wp,-MD,.$(@F).d +DEPS = .*.d + +MAJOR = 1.3 +MINOR = 0 +LIB_NAME = libxutil +LIB_BASE = $(LIB_NAME).so +LIB_MAJOR= $(LIB_BASE).$(MAJOR) +LIB_MINOR= $(LIB_MAJOR).$(MINOR) +LIB = $(LIB_BASE) $(LIB_MAJOR) $(LIB_MINOR) $(LIB_NAME).a + +all: check-for-zlib $(LIB) + +$(LIB_BASE): + ln -sf $(LIB_MAJOR) $@ + +$(LIB_MAJOR): + ln -sf $(LIB_MINOR) $@ + +$(LIB_MINOR): $(LIB_OBJS) + $(CC) -Wl,-soname -Wl,$(LIB_MAJOR) -shared -o $@ $^ + +$(LIB_NAME).a: $(LIB_OBJS) + $(AR) rc $@ $^ + +check-for-zlib: + @if [ ! -e /usr/include/zlib.h ]; then \ + echo "***********************************************************"; \ + echo "ERROR: install zlib header files (http://www.gzip.org/zlib)"; \ + echo "***********************************************************"; \ + false; \ + fi + +install: all + mkdir -p $(prefix)/usr/lib + mkdir -p $(prefix)/usr/include + install -m0755 $(LIB) $(prefix)/usr/lib + +#install -m0644 xc.h $(prefix)/usr/include + +clean: + $(RM) *.a *.so *.o *.rpm $(LIB) + $(RM) *~ + $(RM) $(DEPS) + +-include $(DEPS) diff --git a/tools/libxutil/allocate.c b/tools/libxutil/allocate.c new file mode 100644 index 0000000000..600ebabda6 --- /dev/null +++ b/tools/libxutil/allocate.c @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2001 - 2004 Mike Wray + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "allocate.h" + +/** @file + * Support for allocating memory. + * Usable from user code or kernel code (with __KERNEL__ defined). + * In user code will use GC if USE_GC is defined. + */ + +#ifdef __KERNEL__ +/*----------------------------------------------------------------------------*/ +# include +# include +# include +# include + +# define DEFAULT_TYPE 0 +# define MALLOC(n, type) kmalloc(n, type) +# define FREE(ptr) kfree(ptr) + +/*----------------------------------------------------------------------------*/ +#else /* ! __KERNEL__ */ + +# include +# include + +# define DEFAULT_TYPE 0 + +#ifdef USE_GC +# include "gc.h" +# define MALLOC(n, typ) GC_malloc(n) +# define FREE(ptr) (ptr=NULL) +//typedef void *GC_PTR; +//GC_PTR (*GC_oom_fn)(size_t n); +#else +# define MALLOC(n, type) malloc(n) +# define FREE(ptr) free(ptr) +#endif + +/*----------------------------------------------------------------------------*/ +#endif + +/** Function to call when memory cannot be allocated. */ +AllocateFailedFn *allocate_failed_fn = NULL; + +/** Allocate memory and zero it. + * The type is only relevant when calling from kernel code, + * from user code it is ignored. + * In kernel code the values accepted by kmalloc can be used: + * GFP_USER, GFP_ATOMIC, GFP_KERNEL. + * + * @param size number of bytes to allocate + * @param type memory type to allocate (kernel only) + * @return pointer to the allocated memory or zero + * if malloc failed + */ +void *allocate_type(int size, int type){ + void *p = MALLOC(size, type); + if(p){ + memzero(p, size); + } else if(allocate_failed_fn){ + allocate_failed_fn(size, type); + } + return p; +} + +/** Allocate memory and zero it. + * + * @param size number of bytes to allocate + * @return pointer to the allocated memory or zero + * if malloc failed + */ +void *allocate(int size){ + return allocate_type(size, DEFAULT_TYPE); +} + +/** Free memory allocated by allocate(). + * No-op if 'p' is null. + * + * @param p memory to free + */ +void deallocate(void *p){ + if(p){ + FREE(p); + } +} + +/** Set bytes to zero. + * No-op if 'p' is null. + * + * @param p memory to zero + * @param size number of bytes to zero + */ +void memzero(void *p, int size){ + if(p){ + memset(p, 0, (size_t)size); + } +} + diff --git a/tools/libxutil/allocate.h b/tools/libxutil/allocate.h new file mode 100644 index 0000000000..08bc67b910 --- /dev/null +++ b/tools/libxutil/allocate.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2001 - 2004 Mike Wray + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _XEN_LIB_ALLOCATE_H_ +#define _XEN_LIB_ALLOCATE_H_ + +/** Allocate memory for a given type, and cast. */ +#define ALLOCATE(ctype) (ctype *)allocate(sizeof(ctype)) + +/** Allocate memory for a given type, and cast. */ +#define ALLOCATE_TYPE(ctype, type) (ctype *)allocate(sizeof(ctype)) + +extern void *allocate_type(int size, int type); +extern void *allocate(int size); +extern void deallocate(void *); +extern void memzero(void *p, int size); + +typedef void AllocateFailedFn(int size, int type); +extern AllocateFailedFn *allocate_failed_fn; + +#endif /* _XEN_LIB_ALLOCATE_H_ */ + + + + + + + + + diff --git a/tools/libxutil/debug.h b/tools/libxutil/debug.h new file mode 100644 index 0000000000..4f5228faa3 --- /dev/null +++ b/tools/libxutil/debug.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2004 Mike Wray + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _XEN_LIB_DEBUG_H_ +#define _XEN_LIB_DEBUG_H_ + +#ifndef MODULE_NAME +#define MODULE_NAME "" +#endif + +#ifdef __KERNEL__ +#include +#include + +#ifdef DEBUG + +#define dprintf(fmt, args...) printk(KERN_DEBUG "[DBG] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args) +#define wprintf(fmt, args...) printk(KERN_WARNING "[WRN] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args) +#define iprintf(fmt, args...) printk(KERN_INFO "[INF] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args) +#define eprintf(fmt, args...) printk(KERN_ERR "[ERR] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args) + +#else + +#define dprintf(fmt, args...) do {} while(0) +#define wprintf(fmt, args...) printk(KERN_WARNING "[WRN] " MODULE_NAME fmt, ##args) +#define iprintf(fmt, args...) printk(KERN_INFO "[INF] " MODULE_NAME fmt, ##args) +#define eprintf(fmt, args...) printk(KERN_ERR "[ERR] " MODULE_NAME fmt, ##args) + +#endif + +#else + +#include + +#ifdef DEBUG + +#define dprintf(fmt, args...) fprintf(stdout, "[DBG] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args) +#define wprintf(fmt, args...) fprintf(stderr, "[WRN] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args) +#define iprintf(fmt, args...) fprintf(stderr, "[INF] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args) +#define eprintf(fmt, args...) fprintf(stderr, "[ERR] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args) + +#else + +#define dprintf(fmt, args...) do {} while(0) +#define wprintf(fmt, args...) fprintf(stderr, "[WRN] " MODULE_NAME fmt, ##args) +#define iprintf(fmt, args...) fprintf(stderr, "[INF] " MODULE_NAME fmt, ##args) +#define eprintf(fmt, args...) fprintf(stderr, "[ERR] " MODULE_NAME fmt, ##args) + +#endif + +#endif + +/** Print format for an IP address. + * See NIPQUAD(), HIPQUAD() + */ +#define IPFMT "%u.%u.%u.%u" + +#endif /* ! _XEN_LIB_DEBUG_H_ */ diff --git a/tools/libxutil/enum.c b/tools/libxutil/enum.c new file mode 100644 index 0000000000..95f6e31a87 --- /dev/null +++ b/tools/libxutil/enum.c @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2002, 2004 Mike Wray + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of the + * License, or (at your option) any later version. This library is + * distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef __KERNEL__ +#include +#else +#include +#endif + +#include "sys_string.h" +#include "enum.h" + +/** Map an enum name to its value using a table. + * + * @param name enum name + * @param defs enum definitions + * @return enum value or -1 if not known + */ +int enum_name_to_val(char *name, EnumDef *defs){ + int val = -1; + for(; defs->name; defs++){ + if(!strcmp(defs->name, name)){ + val = defs->val; + break; + } + } + return val; +} + +/** Map an enum value to its name using a table. + * + * @param val enum value + * @param defs enum definitions + * @param defs_n number of definitions + * @return enum name or NULL if not known + */ +char *enum_val_to_name(int val, EnumDef *defs){ + char *name = NULL; + for(; defs->name; defs++){ + if(val == defs->val){ + name = defs->name; + break; + } + } + return name; +} + diff --git a/tools/libxutil/enum.h b/tools/libxutil/enum.h new file mode 100644 index 0000000000..db6e7b0058 --- /dev/null +++ b/tools/libxutil/enum.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2002, 2004 Mike Wray + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of the + * License, or (at your option) any later version. This library is + * distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _XEN_LIB_ENUM_H_ +#define _XEN_LIB_ENUM_H_ + +/** Mapping of an enum value to a name. */ +typedef struct EnumDef { + int val; + char *name; +} EnumDef; + +extern int enum_name_to_val(char *name, EnumDef *defs); +extern char *enum_val_to_name(int val, EnumDef *defs); + +#endif /* _XEN_LIB_ENUM_H_ */ diff --git a/tools/libxutil/file_stream.c b/tools/libxutil/file_stream.c new file mode 100644 index 0000000000..40391f7fa6 --- /dev/null +++ b/tools/libxutil/file_stream.c @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2001 - 2004 Mike Wray + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** @file + * An IOStream implementation using FILE*. + */ +#ifndef __KERNEL__ +#include +#include +#include "allocate.h" +#include "file_stream.h" + +static int file_read(IOStream *s, void *buf, size_t n); +static int file_write(IOStream *s, const void *buf, size_t n); +static int file_error(IOStream *s); +static int file_close(IOStream *s); +static void file_free(IOStream *s); +static int file_flush(IOStream *s); + +/** Methods used by a FILE* IOStream. */ +static const IOMethods file_methods = { + read: file_read, + write: file_write, + error: file_error, + close: file_close, + free: file_free, + flush: file_flush, +}; + +/** IOStream for stdin. */ +static IOStream _iostdin = { + methods: &file_methods, + data: (void*)1, +}; + +/** IOStream for stdout. */ +static IOStream _iostdout = { + methods: &file_methods, + data: (void*)2, +}; + +/** IOStream for stderr. */ +static IOStream _iostderr = { + methods: &file_methods, + data: (void*)3, +}; + +/** IOStream for stdin. */ +IOStream *iostdin = &_iostdin; + +/** IOStream for stdout. */ +IOStream *iostdout = &_iostdout; + +/** IOStream for stderr. */ +IOStream *iostderr = &_iostderr; + +/** Get the underlying FILE*. + * + * @param s file stream + * @return the stream s wraps + */ +static inline FILE *get_file(IOStream *s){ + switch((long)s->data){ + case 1: s->data = stdin; break; + case 2: s->data = stdout; break; + case 3: s->data = stderr; break; + } + return (FILE*)s->data; +} + +/** Control buffering on the underlying stream, like setvbuf(). + * + * @param io file stream + * @param buf buffer + * @param mode buffering mode (see man setvbuf()) + * @param size buffer size + * @return 0 on success, non-zero otherwise + */ +int file_stream_setvbuf(IOStream *io, char *buf, int mode, size_t size){ + return setvbuf(get_file(io), buf, mode, size); +} + +/** Write to the underlying stream using fwrite(); + * + * @param stream input + * @param buf where to put input + * @param n number of bytes to write + * @return number of bytes written + */ +static int file_write(IOStream *s, const void *buf, size_t n){ + return fwrite(buf, 1, n, get_file(s)); +} + +/** Read from the underlying stream using fread(); + * + * @param stream input + * @param buf where to put input + * @param n number of bytes to read + * @return number of bytes read + */ +static int file_read(IOStream *s, void *buf, size_t n){ + return fread(buf, 1, n, get_file(s)); +} + +/** Fush the underlying stream using fflush(). + * + * @param s file stream + * @return 0 on success, error code otherwise + */ +static int file_flush(IOStream *s){ + return fflush(get_file(s)); +} + +/** Check if a stream has an error. + * + * @param s file stream + * @return 1 if has an error, 0 otherwise + */ +static int file_error(IOStream *s){ + return ferror(get_file(s)); +} + +/** Close a file stream. + * + * @param s file stream to close + * @return result of the close + */ +static int file_close(IOStream *s){ + return fclose(get_file(s)); +} + +/** Free a file stream. + * + * @param s file stream + */ +static void file_free(IOStream *s){ + // Do nothing - fclose does it all? +} + +/** Create an IOStream for a stream. + * + * @param f stream to wrap + * @return new IOStream using f for i/o + */ +IOStream *file_stream_new(FILE *f){ + IOStream *io = ALLOCATE(IOStream); + if(io){ + io->methods = &file_methods; + io->data = (void*)f; + } + return io; +} + +/** IOStream version of fopen(). + * + * @param file name of the file to open + * @param flags giving the mode to open in (as for fopen()) + * @return new stream for the open file, or 0 if failed + */ +IOStream *file_stream_fopen(const char *file, const char *flags){ + IOStream *io = 0; + FILE *fin = fopen(file, flags); + if(fin){ + io = file_stream_new(fin); + if(!io){ + fclose(fin); + //free(fin); // fclose frees ? + } + } + return io; +} + +/** IOStream version of fdopen(). + * + * @param fd file descriptor + * @param flags giving the mode to open in (as for fdopen()) + * @return new stream for the open file, or 0 if failed + */ +IOStream *file_stream_fdopen(int fd, const char *flags){ + IOStream *io = 0; + FILE *fin = fdopen(fd, flags); + if(fin){ + io = file_stream_new(fin); + } + return io; +} +#endif diff --git a/tools/libxutil/file_stream.h b/tools/libxutil/file_stream.h new file mode 100644 index 0000000000..36a0f928b2 --- /dev/null +++ b/tools/libxutil/file_stream.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2001 - 2004 Mike Wray + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _XEN_LIB_FILE_STREAM_H_ +#define _XEN_LIB_FILE_STREAM_H_ + +#ifndef __KERNEL__ +#include "iostream.h" +#include + +extern IOStream *file_stream_new(FILE *f); +extern IOStream *file_stream_fopen(const char *file, const char *flags); +extern IOStream *file_stream_fdopen(int fd, const char *flags); +extern IOStream get_stream_stdout(void); +extern IOStream get_stream_stderr(void); +extern IOStream get_stream_stdin(void); + +extern int file_stream_setvbuf(IOStream *io, char *buf, int mode, size_t size); +#endif +#endif /* !_XEN_LIB_FILE_STREAM_H_ */ diff --git a/tools/libxutil/gzip_stream.c b/tools/libxutil/gzip_stream.c new file mode 100644 index 0000000000..af46023f9d --- /dev/null +++ b/tools/libxutil/gzip_stream.c @@ -0,0 +1,171 @@ +/* $Id: gzip_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $ */ +/* + * Copyright (C) 2003 Hewlett-Packard Company. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** @file + * An IOStream implementation using zlib gzFile to provide + * compression and decompression. + */ +#ifndef __KERNEL__ + +#include +#include + +#include "zlib.h" + +#include "allocate.h" +#include "gzip_stream.h" + +static int gzip_read(IOStream *s, void *buf, size_t n); +static int gzip_write(IOStream *s, const void *buf, size_t n); +static int gzip_error(IOStream *s); +static int gzip_close(IOStream *s); +static void gzip_free(IOStream *s); +static int gzip_flush(IOStream *s); + +/** Methods used by a gzFile* IOStream. */ +static const IOMethods gzip_methods = { + read: gzip_read, + write: gzip_write, + error: gzip_error, + close: gzip_close, + free: gzip_free, + flush: gzip_flush, +}; + +/** Get the underlying gzFile*. + * + * @param s gzip stream + * @return the stream s wraps + */ +static inline gzFile get_gzfile(IOStream *s){ + return (gzFile)s->data; +} + +/** Write to the underlying stream. + * + * @param stream destination + * @param buf data + * @param n number of bytes to write + * @return number of bytes written + */ +static int gzip_write(IOStream *s, const void *buf, size_t n){ + return gzwrite(get_gzfile(s), (void*)buf, n); +} + +/** Read from the underlying stream. + * + * @param stream input + * @param buf where to put input + * @param n number of bytes to read + * @return number of bytes read + */ +static int gzip_read(IOStream *s, void *buf, size_t n){ + return gzread(get_gzfile(s), buf, n); +} + +/** Flush the underlying stream. + * + * @param s gzip stream + * @return 0 on success, error code otherwise + */ +static int gzip_flush(IOStream *s){ + //return gzflush(get_gzfile(s), Z_NO_FLUSH); + return gzflush(get_gzfile(s), Z_SYNC_FLUSH); + //return gzflush(get_gzfile(s), Z_FULL_FLUSH); +} + +/** Check if a stream has an error. + * + * @param s gzip stream + * @return 1 if has an error, 0 otherwise + */ +static int gzip_error(IOStream *s){ + int err; + gzFile *gz = get_gzfile(s); + gzerror(gz, &err); + return (err == Z_ERRNO ? 1 /* ferror(gzfile(gz)) */ : err); +} + +/** Close a gzip stream. + * + * @param s gzip stream to close + * @return result of the close + */ +static int gzip_close(IOStream *s){ + return gzclose(get_gzfile(s)); +} + +/** Free a gzip stream. + * + * @param s gzip stream + */ +static void gzip_free(IOStream *s){ + // Do nothing - fclose does it all? +} + +/** Create an IOStream for a gzip stream. + * + * @param f stream to wrap + * @return new IOStream using f for i/o + */ +IOStream *gzip_stream_new(gzFile *f){ + IOStream *io = ALLOCATE(IOStream); + if(io){ + io->methods = &gzip_methods; + io->data = (void*)f; + } + return io; +} + +/** IOStream version of fopen(). + * + * @param file name of the file to open + * @param flags giving the mode to open in (as for fopen()) + * @return new stream for the open file, or NULL if failed + */ +IOStream *gzip_stream_fopen(const char *file, const char *flags){ + IOStream *io = NULL; + gzFile *fgz; + fgz = gzopen(file, flags); + if(fgz){ + io = gzip_stream_new(fgz); + if(!io){ + gzclose(fgz); + //free(fgz); // gzclose frees ? + } + } + return io; +} + +/** IOStream version of fdopen(). + * + * @param fd file descriptor + * @param flags giving the mode to open in (as for fdopen()) + * @return new stream for the open file, or NULL if failed + */ +IOStream *gzip_stream_fdopen(int fd, const char *flags){ + IOStream *io = NULL; + gzFile *fgz; + fgz = gzdopen(fd, flags); + if(fgz){ + io = gzip_stream_new(fgz); + } + return io; +} +#endif diff --git a/tools/libxutil/gzip_stream.h b/tools/libxutil/gzip_stream.h new file mode 100644 index 0000000000..cf76d25275 --- /dev/null +++ b/tools/libxutil/gzip_stream.h @@ -0,0 +1,31 @@ +#/* $Id: gzip_stream.h,v 1.3 2003/09/30 15:22:53 mjw Exp $ */ +/* + * Copyright (C) 2003 Hewlett-Packard Company. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _SP_GZIP_STREAM_H_ +#define _SP_GZIP_STREAM_H_ + +#ifndef __KERNEL__ +#include "iostream.h" +#include "zlib.h" + +extern IOStream *gzip_stream_new(gzFile *f); +extern IOStream *gzip_stream_fopen(const char *file, const char *flags); +extern IOStream *gzip_stream_fdopen(int fd, const char *flags); +#endif +#endif /* !_SP_FILE_STREAM_H_ */ diff --git a/tools/libxutil/hash_table.c b/tools/libxutil/hash_table.c new file mode 100644 index 0000000000..13da946e77 --- /dev/null +++ b/tools/libxutil/hash_table.c @@ -0,0 +1,640 @@ +/* + * Copyright (C) 2001 - 2004 Mike Wray + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef __KERNEL__ +# include +# include +# include +# include +#else +# include +# include +#endif + +//#include + +#include "allocate.h" +#include "hash_table.h" + +/** @file + * Base support for hashtables. + * + * Hash codes are reduced modulo the number of buckets to index tables, + * so there is no need for hash functions to limit the range of hashcodes. + * In fact it is assumed that hashcodes do not change when the number of + * buckets in the table changes. + */ + +/*==========================================================================*/ +/** Number of bits in half a word. */ +//#if __WORDSIZE == 64 +//#define HALF_WORD_BITS 32 +//#else +#define HALF_WORD_BITS 16 +//#endif + +/** Mask for lo half of a word. On 32-bit this is + * (1<<16) - 1 = 65535 = 0xffff + * It's 4294967295 = 0xffffffff on 64-bit. + */ +#define LO_HALF_MASK ((1 << HALF_WORD_BITS) - 1) + +/** Get the lo half of a word. */ +#define LO_HALF(x) ((x) & LO_HALF_MASK) + +/** Get the hi half of a word. */ +#define HI_HALF(x) ((x) >> HALF_WORD_BITS) + +/** Do a full hash on both inputs, using DES-style non-linear scrambling. + * Both inputs are replaced with the results of the hash. + * + * @param pleft input/output word + * @param pright input/output word + */ +void pseudo_des(unsigned long *pleft, unsigned long *pright){ + // Bit-rich mixing constant. + static const unsigned long a_mixer[] = { + 0xbaa96887L, 0x1e17d32cL, 0x03bcdc3cL, 0x0f33d1b2L, }; + + // Bit-rich mixing constant. + static const unsigned long b_mixer[] = { + 0x4b0f3b58L, 0xe874f0c3L, 0x6955c5a6L, 0x55a7ca46L, }; + + // Number of iterations - must be 2 or 4. + static const int ncycle = 4; + //static const int ncycle = 2; + + unsigned long left = *pleft, right = *pright; + unsigned long v, v_hi, v_lo; + int i; + + for(i=0; ibuckets + (hashcode % table->buckets_n); +} + +/** Initialize a hash table. + * Can be safely called more than once. + * + * @param table to initialize + */ +void HashTable_init(HashTable *table){ + int i; + + if(!table->init_done){ + table->init_done = 1; + table->next_id = 0; + for(i=0; ibuckets_n; i++){ + HTBucket *bucket = get_bucket(table, i); + bucket->head = 0; + bucket->count = 0; + } + table->entry_count = 0; + } +} + +/** Allocate a new hashtable. + * If the number of buckets is not positive the default is used. + * The number of buckets should usually be prime. + * + * @param buckets_n number of buckets + * @return new hashtable or null + */ +HashTable *HashTable_new(int buckets_n){ + HashTable *z = ALLOCATE(HashTable); + if(!z) goto exit; + if(buckets_n <= 0){ + buckets_n = HT_BUCKETS_N; + } + z->buckets = (HTBucket*)allocate(buckets_n * sizeof(HTBucket)); + if(!z->buckets){ + deallocate(z); + z = 0; + goto exit; + } + z->buckets_n = buckets_n; + HashTable_init(z); + exit: + return z; +} + +/** Free a hashtable. + * Any entries are removed and freed. + * + * @param h hashtable (ignored if null) + */ +void HashTable_free(HashTable *h){ + if(h){ + HashTable_clear(h); + deallocate(h->buckets); + deallocate(h); + } +} + +/** Push an entry on the list in the bucket for a given hashcode. + * + * @param table to add entry to + * @param hashcode for the entry + * @param entry to add + */ +static inline void push_on_bucket(HashTable *table, Hashcode hashcode, + HTEntry *entry){ + HTBucket *bucket; + HTEntry *old_head; + + bucket = get_bucket(table, hashcode); + old_head = bucket->head; + bucket->count++; + bucket->head = entry; + entry->next = old_head; +} + +/** Change the number of buckets in a hashtable. + * No-op if the number of buckets is not positive. + * Existing entries are reallocated to buckets based on their hashcodes. + * The table is unmodified if the number of buckets cannot be changed. + * + * @param table hashtable + * @param buckets_n new number of buckets + * @return 0 on success, error code otherwise + */ +int HashTable_set_buckets_n(HashTable *table, int buckets_n){ + int err = 0; + HTBucket *old_buckets = table->buckets; + int old_buckets_n = table->buckets_n; + int i; + + if(buckets_n <= 0){ + err = -EINVAL; + goto exit; + } + table->buckets = (HTBucket*)allocate(buckets_n * sizeof(HTBucket)); + if(!table->buckets){ + err = -ENOMEM; + table->buckets = old_buckets; + goto exit; + } + table->buckets_n = buckets_n; + for(i=0; ihead; entry; entry = next){ + next = entry->next; + push_on_bucket(table, entry->hashcode, entry); + } + } + deallocate(old_buckets); + exit: + return err; +} + +/** Adjust the number of buckets so the table is neither too full nor too empty. + * The table is unmodified if adjusting fails. + * + * @param table hash table + * @param buckets_min minimum number of buckets (use default if 0 or negative) + * @return 0 on success, error code otherwise + */ +int HashTable_adjust(HashTable *table, int buckets_min){ + int buckets_n = 0; + int err = 0; + if(buckets_min <= 0) buckets_min = HT_BUCKETS_N; + if(table->entry_count >= table->buckets_n){ + // The table is dense - expand it. + buckets_n = 2 * table->buckets_n; + } else if((table->buckets_n > buckets_min) && + (4 * table->entry_count < table->buckets_n)){ + // The table is more than minimum size and sparse - shrink it. + buckets_n = 2 * table->entry_count; + if(buckets_n < buckets_min) buckets_n = buckets_min; + } + if(buckets_n){ + err = HashTable_set_buckets_n(table, buckets_n); + } + return err; +} + +/** Allocate a new entry for a given value. + * + * @param value to put in the entry + * @return entry, or 0 on failure + */ +HTEntry * HTEntry_new(Hashcode hashcode, void *key, void *value){ + HTEntry *z = ALLOCATE(HTEntry); + if(z){ + z->hashcode = hashcode; + z->key = key; + z->value = value; + } + return z; +} + +/** Free an entry. + * + * @param z entry to free + */ +inline void HTEntry_free(HTEntry *z){ + if(z){ + deallocate(z); + } +} + +/** Free an entry in a hashtable. + * The table's entry_free_fn is used is defined, otherwise + * the HTEntry itself is freed. + * + * @param table hashtable + * @param entry to free + */ +inline void HashTable_free_entry(HashTable *table, HTEntry *entry){ + if(!entry)return; + if(table && table->entry_free_fn){ + table->entry_free_fn(table, entry); + } else { + HTEntry_free(entry); + } +} + +/** Get the first entry satisfying a test from the bucket for the + * given hashcode. + * + * @param table to look in + * @param hashcode indicates the bucket + * @param test_fn test to apply to elements + * @param arg first argument to calls to test_fn + * @return entry found, or 0 + */ +inline HTEntry * HashTable_find_entry(HashTable *table, Hashcode hashcode, + TableTestFn *test_fn, TableArg arg){ + HTBucket *bucket; + HTEntry *entry = 0; + HTEntry *next; + + bucket = get_bucket(table, hashcode); + for(entry = bucket->head; entry; entry = next){ + next = entry->next; + if(test_fn(arg, table, entry)){ + break; + } + } + return entry; +} + +/** Test hashtable keys for equality. + * Uses the table's key_equal_fn if defined, otherwise pointer equality. + * + * @param key1 key to compare + * @param key2 key to compare + * @return 1 if equal, 0 otherwise + */ +inline int HashTable_key_equal(HashTable *table, void *key1, void *key2){ + return (table->key_equal_fn ? table->key_equal_fn(key1, key2) : key1==key2); +} + +/** Compute the hashcode of a hashtable key. + * The table's key_hash_fn is used if defined, otherwise the address of + * the key is hashed. + * + * @param table hashtable + * @param key to hash + * @return hashcode + */ +inline Hashcode HashTable_key_hash(HashTable *table, void *key){ + return (table->key_hash_fn ? table->key_hash_fn(key) : hash_ul((unsigned long)key)); +} + +/** Test if an entry has a given key. + * + * @param arg containing key to test for + * @param table the entry is in + * @param entry to test + * @return 1 if the entry has the key, 0 otherwise + */ +static inline int has_key(TableArg arg, HashTable *table, HTEntry *entry){ + return HashTable_key_equal(table, arg.ptr, entry->key); +} + +/** Get an entry with a given key. + * + * @param table to search + * @param key to look for + * @return entry if found, null otherwise + */ +#if 0 +inline HTEntry * HashTable_get_entry(HashTable *table, void *key){ + TableArg arg = { ptr: key }; + return HashTable_find_entry(table, HashTable_key_hash(table, key), has_key, arg); +} +#else +inline HTEntry * HashTable_get_entry(HashTable *table, void *key){ + Hashcode hashcode; + HTBucket *bucket; + HTEntry *entry = 0; + HTEntry *next; + + hashcode = HashTable_key_hash(table, key); + bucket = get_bucket(table, hashcode); + for(entry = bucket->head; entry; entry = next){ + next = entry->next; + if(HashTable_key_equal(table, key, entry->key)){ + break; + } + } + return entry; +} +#endif + +/** Get the value of an entry with a given key. + * + * @param table to search + * @param key to look for + * @return value if an entry was found, null otherwise + */ +inline void * HashTable_get(HashTable *table, void *key){ + HTEntry *entry = HashTable_get_entry(table, key); + return (entry ? entry->value : 0); +} + +/** Print the buckets in a table. + * + * @param table to print + */ +void show_buckets(HashTable *table, IOStream *io){ + int i,j ; + IOStream_print(io, "entry_count=%d buckets_n=%d\n", table->entry_count, table->buckets_n); + for(i=0; ibuckets_n; i++){ + if(0 || table->buckets[i].count>0){ + IOStream_print(io, "bucket %3d %3d %10p ", i, + table->buckets[i].count, + table->buckets[i].head); + for(j = table->buckets[i].count; j>0; j--){ + IOStream_print(io, "+"); + } + IOStream_print(io, "\n"); + } + } + HashTable_print(table, io); +} + +/** Print an entry in a table. + * + * @param entry to print + * @param arg a pointer to an IOStream to print to + * @return 0 + */ +static int print_entry(TableArg arg, HashTable *table, HTEntry *entry){ + IOStream *io = (IOStream*)arg.ptr; + IOStream_print(io, " b=%4lx h=%08lx i=%08lx |-> e=%8p k=%8p v=%8p\n", + entry->hashcode % table->buckets_n, + entry->hashcode, + entry->index, + entry, entry->key, entry->value); + return 0; +} + +/** Print a hash table. + * + * @param table to print + */ +void HashTable_print(HashTable *table, IOStream *io){ + IOStream_print(io, "{\n"); + HashTable_map(table, print_entry, (TableArg){ ptr: io }); + IOStream_print(io, "}\n"); +} +/*==========================================================================*/ + +/** Get the next entry id to use for a table. + * + * @param table hash table + * @return non-zero entry id + */ +static inline unsigned long get_next_id(HashTable *table){ + unsigned long id; + + if(table->next_id == 0){ + table->next_id = 1; + } + id = table->next_id++; + return id; +} + +/** Add an entry to the bucket for the + * given hashcode. + * + * @param table to insert in + * @param hashcode indicates the bucket + * @param key to add an entry for + * @param value to add an entry for + * @return entry on success, 0 on failure + */ +inline HTEntry * HashTable_add_entry(HashTable *table, Hashcode hashcode, void *key, void *value){ + HTEntry *entry = HTEntry_new(hashcode, key, value); + if(entry){ + entry->index = get_next_id(table); + push_on_bucket(table, hashcode, entry); + table->entry_count++; + } + return entry; +} + +/** Move the front entry for a bucket to the correct point in the bucket order as + * defined by the order function. If this is called every time a new entry is added + * the bucket will be maintained in sorted order. + * + * @param table to modify + * @param hashcode indicates the bucket + * @param order entry comparison function + * @return 0 if an entry was moved, 1 if not + */ +int HashTable_order_bucket(HashTable *table, Hashcode hashcode, TableOrderFn *order){ + HTEntry *new_entry = NULL, *prev = NULL, *entry = NULL; + HTBucket *bucket; + int err = 1; + + bucket = get_bucket(table, hashcode); + new_entry = bucket->head; + if(!new_entry || !new_entry->next) goto exit; + for(entry = new_entry->next; entry; prev = entry, entry = entry->next){ + if(order(new_entry, entry) <= 0) break; + } + if(prev){ + err = 0; + bucket->head = new_entry->next; + new_entry->next = entry; + prev->next = new_entry; + } + exit: + return err; +} + +/** Add an entry to a hashtable. + * The entry is added to the bucket for its key's hashcode. + * + * @param table to insert in + * @param key to add an entry for + * @param value to add an entry for + * @return entry on success, 0 on failure + */ +inline HTEntry * HashTable_add(HashTable *table, void *key, void *value){ + return HashTable_add_entry(table, HashTable_key_hash(table, key), key, value); +} + + +/** Remove entries satisfying a test from the bucket for the + * given hashcode. + * + * @param table to remove from + * @param hashcode indicates the bucket + * @param test_fn test to apply to elements + * @param arg first argument to calls to test_fn + * @return number of entries removed + */ +inline int HashTable_remove_entry(HashTable *table, Hashcode hashcode, + TableTestFn *test_fn, TableArg arg){ + HTBucket *bucket; + HTEntry *entry, *prev = 0, *next; + int removed_count = 0; + + bucket = get_bucket(table, hashcode); + for(entry = bucket->head; entry; entry = next){ + next = entry->next; + if(test_fn(arg, table, entry)){ + if(prev){ + prev->next = next; + } else { + bucket->head = next; + } + bucket->count--; + table->entry_count--; + removed_count++; + HashTable_free_entry(table, entry); + entry = 0; + } + prev = entry; + } + return removed_count; +} + +/** Remove entries with a given key. + * + * @param table to remove from + * @param key of entries to remove + * @return number of entries removed + */ +inline int HashTable_remove(HashTable *table, void *key){ +#if 1 + Hashcode hashcode; + HTBucket *bucket; + HTEntry *entry, *prev = 0, *next; + int removed_count = 0; + + hashcode = HashTable_key_hash(table, key); + bucket = get_bucket(table, hashcode); + for(entry = bucket->head; entry; entry = next){ + next = entry->next; + if(HashTable_key_equal(table, key, entry->key)){ + if(prev){ + prev->next = next; + } else { + bucket->head = next; + } + bucket->count--; + table->entry_count--; + removed_count++; + HashTable_free_entry(table, entry); + entry = 0; + } + prev = entry; + } + return removed_count; +#else + return HashTable_remove_entry(table, HashTable_key_hash(table, key), + has_key, (TableArg){ ptr: key}); +#endif +} + +/** Remove (and free) all the entries in a bucket. + * + * @param bucket to clear + */ +static inline void bucket_clear(HashTable *table, HTBucket *bucket){ + HTEntry *entry, *next; + + for(entry = bucket->head; entry; entry = next){ + next = entry->next; + HashTable_free_entry(table, entry); + } + bucket->head = 0; + table->entry_count -= bucket->count; + bucket->count = 0; +} + +/** Remove (and free) all the entries in a table. + * + * @param table to clear + */ +void HashTable_clear(HashTable *table){ + int i, n = table->buckets_n; + + for(i=0; ibuckets + i); + } +} diff --git a/tools/libxutil/hash_table.h b/tools/libxutil/hash_table.h new file mode 100644 index 0000000000..6d7e76ff33 --- /dev/null +++ b/tools/libxutil/hash_table.h @@ -0,0 +1,295 @@ +/* $Id: hash_table.h,v 1.1 2004/03/30 16:21:26 mjw Exp $ */ +/* + * Copyright (C) 2001 - 2004 Mike Wray + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _XEN_LIB_HASH_TABLE_H_ +#define _XEN_LIB_HASH_TABLE_H_ + +#include "iostream.h" + +typedef unsigned long Hashcode; + +/** Type used to pass parameters to table functions. */ +typedef union TableArg { + unsigned long ul; + void *ptr; +} TableArg; + +/** An entry in a bucket list. */ +typedef struct HTEntry { + /** Hashcode of the entry's key. */ + Hashcode hashcode; + /** Identifier for this entry in the table. */ + int index; + /** The key for this entry. */ + void *key; + /** The value in this entry. */ + void *value; + /** The next entry in the list. */ + struct HTEntry *next; +} HTEntry; + +/** A bucket in a rule table. */ +typedef struct HTBucket { + /** Number of entries in the bucket. */ + int count; + /** First entry in the bucket (may be null). */ + HTEntry *head; +} HTBucket; + +/** Default number of buckets in a hash table. + * You want enough buckets so the lists in the buckets will typically be short. + * It's a good idea if this is prime, since that will help to spread hashcodes + * around the table. + */ +//#define HT_BUCKETS_N 1 +//#define HT_BUCKETS_N 3 +//#define HT_BUCKETS_N 7 +//#define HT_BUCKETS_N 17 +//#define HT_BUCKETS_N 97 +//#define HT_BUCKETS_N 211 +//#define HT_BUCKETS_N 401 +#define HT_BUCKETS_N 1021 + +typedef struct HashTable HashTable; + +/** Type for a function used to select table entries. */ +typedef int TableTestFn(TableArg arg, HashTable *table, HTEntry *entry); + +/** Type for a function to map over table entries. */ +typedef int TableMapFn(TableArg arg, HashTable *table, HTEntry *entry); + +/** Type for a function to free table entries. */ +typedef void TableFreeFn(HashTable *table, HTEntry *entry); + +/** Type for a function to hash table keys. */ +typedef Hashcode TableHashFn(void *key); + +/** Type for a function to test table keys for equality. */ +typedef int TableEqualFn(void *key1, void *key2); + +/** Type for a function to order table entries. */ +typedef int TableOrderFn(HTEntry *e1, HTEntry *e2); + +/** General hash table. + * A hash table with a list in each bucket. + * Functions can be supplied for freeing entries, hashing keys, and comparing keys. + * These all default to 0, when default behaviour treating keys as integers is used. + */ +struct HashTable { + /** Flag indicating whether the table has been initialised. */ + int init_done; + /** Next value for the id field in inserted rules. */ + unsigned long next_id; + /** Number of buckets in the bucket array. */ + int buckets_n; + /** Array of buckets, each with its own list. */ + HTBucket *buckets; + /** Number of entries in the table. */ + int entry_count; + /** Function to free keys and values in entries. */ + TableFreeFn *entry_free_fn; + /** Function to hash keys. */ + TableHashFn *key_hash_fn; + /** Function to compare keys for equality. */ + TableEqualFn *key_equal_fn; + /** Place for the user of the table to hang extra data. */ + void *user_data; +}; + +extern HashTable *HashTable_new(int bucket_n); +extern void HashTable_free(HashTable *table); +extern HTEntry * HTEntry_new(Hashcode hashcode, void *key, void *value); +extern void HTEntry_free(HTEntry *entry); +extern int HashTable_set_bucket_n(HashTable *table, int bucket_n); +extern void HashTable_clear(HashTable *table); +extern HTEntry * HashTable_add_entry(HashTable *table, Hashcode hashcode, void *key, void *value); +extern HTEntry * HashTable_get_entry(HashTable *table, void *key); +extern HTEntry * HashTable_add(HashTable *table, void *key, void *value); +extern void * HashTable_get(HashTable *table, void *key); +extern int HashTable_remove(HashTable *table, void *key); +extern HTEntry * HashTable_find_entry(HashTable *table, Hashcode hashcode, + TableTestFn *test_fn, TableArg arg); +extern int HashTable_remove_entry(HashTable *table, Hashcode hashcode, + TableTestFn *test_fn, TableArg arg); +//extern int HashTable_map(HashTable *table, TableMapFn *map_fn, TableArg arg); +extern void HashTable_print(HashTable *table, IOStream *out); +extern int HashTable_set_buckets_n(HashTable *table, int buckets_n); +extern int HashTable_adjust(HashTable *table, int buckets_min); +extern void pseudo_des(unsigned long *pleft, unsigned long *pright); +extern Hashcode hash_string(char *s); + +extern int HashTable_order_bucket(HashTable *table, Hashcode hashcode, TableOrderFn *order); + +/** Control whether to use hashing based on DES or simple + * hashing. DES hashing is `more random' but much more expensive. + */ +#define HASH_PSEUDO_DES 0 + +/** Hash a long using a quick and dirty linear congruential random number generator. + * See `Numerical Recipes in C', Chapter 7, "An Even Quicker Generator". + * + * @param a value to hash + * @return hashed input + */ +static inline unsigned long lcrng_hash(unsigned long a){ + return (1664525L * a + 1013904223L); +} + +/** Hash an unsigned long. + * + * @param a input to hash + * @return hashcode + */ +static inline Hashcode hash_ul(unsigned long a){ +#if HASH_PSEUDO_DES + unsigned long left = a; + unsigned long right = 0L; + pseudo_des(&left, &right); + return right; +#else + a = lcrng_hash(a); + a = lcrng_hash(a); + return a; +#endif +} + +/** Hash two unsigned longs together. + * + * @param a input to hash + * @param b input to hash + * @return hashcode + */ +static inline Hashcode hash_2ul(unsigned long a, unsigned long b){ +#if HASH_PSEUDO_DES + unsigned long left = a; + unsigned long right = b; + pseudo_des(&left, &right); + return right; +#else + a = lcrng_hash(a); + a ^= b; + a = lcrng_hash(a); + return a; +#endif +} + +/** Hash a hashcode and an unsigned long together. + * + * @param a input hashcode + * @param b input to hash + * @return hashcode + */ +static inline Hashcode hash_hul(Hashcode a, unsigned long b){ +#if HASH_PSEUDO_DES + unsigned long left = a; + unsigned long right = b; + pseudo_des(&left, &right); + return right; +#else + a ^= b; + a = lcrng_hash(a); + return a; +#endif +} + +/** Macro to declare variables for HashTable_for_each() to use. + * + * @param entry variable that is set to entries in the table + */ +#define HashTable_for_decl(entry) \ + HashTable *_var_table; \ + HTBucket *_var_bucket; \ + HTBucket *_var_end; \ + HTEntry *_var_next; \ + HTEntry *entry + +/** Macro to iterate over the entries in a hashtable. + * Must be in a scope where HashTable_for_decl() has been used to declare + * variables for it to use. + * The variable 'entry' is iterated over entries in the table. + * The code produced is syntactically a loop, so it must be followed by + * a loop body, typically some statements in braces: + * HashTable_for_each(entry, table){ ...loop body... } + * + * HashTable_for_each() and HashTable_for_decl() cannot be used for nested + * loops as variables will clash. + * + * @note The simplest way to code a direct loop over the entries in a hashtable + * is to use a loop over the buckets, with a nested loop over the entries + * in a bucket. Using this approach in a macro means the macro contains + * an opening brace, and calls to it must be followed by 2 braces! + * To avoid this the code has been restructured so that it is a for loop. + * So that statements could be used in the test expression of the for loop, + * we have used the gcc statement expression extension ({ ... }). + * + * @param entry variable to iterate over the entries + * @param table to iterate over (non-null) + */ +#define HashTable_for_each(entry, table) \ + _var_table = table; \ + _var_bucket = _var_table->buckets; \ + _var_end = _var_bucket + _var_table->buckets_n; \ + for(entry=0, _var_next=0; \ + ({ if(_var_next){ \ + entry = _var_next; \ + _var_next = entry->next; \ + } else { \ + while(_var_bucket < _var_end){ \ + entry = _var_bucket->head; \ + _var_bucket++; \ + if(entry){ \ + _var_next = entry->next; \ + break; \ + } \ + } \ + }; \ + entry; }); \ + entry = _var_next ) + +/** Map a function over the entries in a table. + * Mapping stops when the function returns a non-zero value. + * Uses the gcc statement expression extension ({ ... }). + * + * @param table to map over + * @param fn function to apply to entries + * @param arg first argument to call the function with + * @return 0 if fn always returned 0, first non-zero value otherwise + */ +#define HashTable_map(table, fn, arg) \ + ({ HashTable_for_decl(_var_entry); \ + TableArg _var_arg = arg; \ + int _var_value = 0; \ + HashTable_for_each(_var_entry, table){ \ + if((_var_value = fn(_var_arg, _var_table, _var_entry))) break; \ + } \ + _var_value; }) + +/** Cast x to the type for a key or value in a hash table. + * This avoids compiler warnings when using short integers + * as keys or values (especially on 64-bit platforms). + */ +#define HKEY(x) ((void*)(unsigned long)(x)) + +/** Cast x from the type for a key or value in a hash table. + * to an unsigned long. This avoids compiler warnings when using + * short integers as keys or values (especially on 64-bit platforms). + */ +#define HVAL(x) ((unsigned long)(x)) + +#endif /* !_XEN_LIB_HASH_TABLE_H_ */ diff --git a/tools/libxutil/iostream.c b/tools/libxutil/iostream.c new file mode 100644 index 0000000000..e9980838f7 --- /dev/null +++ b/tools/libxutil/iostream.c @@ -0,0 +1,37 @@ +#include "iostream.h" +#include "sys_string.h" + +/** Print on a stream, like vfprintf(). + * + * @param stream to print to + * @param format for the print (as fprintf()) + * @param args arguments to print + * @return result code from the print + */ +int IOStream_vprint(IOStream *stream, const char *format, va_list args){ + char buffer[1024]; + int k = sizeof(buffer), n; + + n = vsnprintf(buffer, k, (char*)format, args); + if(n < 0 || n > k ){ + n = k; + } + n = IOStream_write(stream, buffer, n); + return n; +} + +/** Print on a stream, like fprintf(). + * + * @param stream to print to + * @param format for the print (as fprintf()) + * @return result code from the print + */ +int IOStream_print(IOStream *stream, const char *format, ...){ + va_list args; + int result = -1; + + va_start(args, format); + result = IOStream_vprint(stream, format, args); + va_end(args); + return result; +} diff --git a/tools/libxutil/iostream.h b/tools/libxutil/iostream.h new file mode 100644 index 0000000000..5dbe14a0b4 --- /dev/null +++ b/tools/libxutil/iostream.h @@ -0,0 +1,243 @@ +#ifndef _XC_LINUX_SAVE_H_ +#define _XC_LINUX_SAVE_H_ + +#include +#include +#include + +#ifdef __KERNEL__ +#include +#else +#include +#endif + +#include "allocate.h" + +/** End of input return value. */ +#define IOSTREAM_EOF -1 + +/** An input/output abstraction. + */ +typedef struct IOStream IOStream; + +/** Record of the functions to use for operations on an + * IOStream implementation. + */ +typedef struct IOMethods { + /** Read function. Called with the user data, buffer to read into + * and number of bytes to read. Must return number of bytes read + * on success, less than zero on error. + */ + int (*read)(IOStream *stream, void *buf, size_t n); + + /** Write function. Called with user data, buffer to write and + * number of bytes to write. Must return number of bytes written on + * success, less than zero otherwise. + */ + int (*write)(IOStream *stream, const void *buf, size_t n); + + int (*flush)(IOStream *s); + + int (*error)(IOStream *s); + + int (*close)(IOStream *s); + + void (*free)(IOStream *s); + + void (*lock)(IOStream *s); + void (*unlock)(IOStream *s); + +} IOMethods; + +/** Abstract i/o object. + */ +struct IOStream { + /** Methods to use to implement operations. */ + const IOMethods *methods; + /** Private state for the implementation. */ + const void *data; + /** Flag indicating whether the stream is closed. */ + int closed; + /** Number of bytes written. */ + int written; + /** Number of bytes read. */ + int read; +}; + + +/** IOStream version of stdin. */ +extern IOStream *iostdin; + +/** IOStream version of stdout, */ +extern IOStream *iostdout; + +/** IOStream version of stderr. */ +extern IOStream *iostderr; + +extern int IOStream_print(IOStream *io, const char *format, ...); +extern int IOStream_vprint(IOStream *io, const char *format, va_list args); + +/** Read from a stream. + * + * @param stream input + * @param buf where to put input + * @param n number of bytes to read + * @return if ok, number of bytes read, otherwise negative error code + */ +static inline int IOStream_read(IOStream *stream, void *buf, size_t n){ + int result = 0; + if(stream->closed) goto exit; + if(!stream->methods || !stream->methods->read){ + result = -EINVAL; + goto exit; + } + result = stream->methods->read(stream, buf, n); + if(result > 0){ + stream->read += result; + } + exit: + return result; +} + +/** Write to a stream. + * + * @param stream input + * @param buf where to put input + * @param n number of bytes to write + * @return if ok, number of bytes read, otherwise negative error code + */ +static inline int IOStream_write(IOStream *stream, const void *buf, size_t n){ + int result = 0; + if(stream->closed) goto exit; + if(!stream->methods || !stream->methods->write){ + result = -EINVAL; + goto exit; + } + result = stream->methods->write(stream, buf, n); + if(result > 0){ + stream->written += result; + } + exit: + return result; +} + +/** Flush the stream. + * + * @param stream stream + * @return 0 on success, IOSTREAM_EOF otherwise + */ +static inline int IOStream_flush(IOStream *stream){ + int result = 0; + if(stream->closed){ + result = IOSTREAM_EOF; + } else if(stream->methods->flush){ + result = stream->methods->flush(stream); + if(result < 0) result = IOSTREAM_EOF; + } + return result; +} + +/** Check whether the stream has an error. + * + * @param stream to check + * @return 1 for error, 0 otherwise + */ +static inline int IOStream_error(IOStream *stream){ + int err = 0; + if(stream->methods && stream->methods->error){ + err = stream->methods->error(stream); + } + return err; +} + +/** Close the stream. + * + * @param stream to close + * @return 1 for error, 0 otherwise + */ +static inline int IOStream_close(IOStream *stream){ + int err = 1; + if(stream->methods && stream->methods->close){ + err = stream->methods->close(stream); + } + return err; +} + +/** Test if the stream has been closed. + * + * @param stream to check + * @return 1 if closed, 0 otherwise + */ +static inline int IOStream_is_closed(IOStream *stream){ + return stream->closed; +} + +/** Free the memory used by the stream. + * + * @param stream to free + */ +static inline void IOStream_free(IOStream *stream){ + if(stream->methods && stream->methods->free){ + stream->methods->free(stream); + } + *stream = (IOStream){}; + deallocate(stream); +} + + +/** Print a character to a stream, like fputc(). + * + * @param stream to print to + * @param c character to print + * @return result code from the print + */ +static inline int IOStream_putc(IOStream *stream, int c){ + int err; + unsigned char b = (unsigned char)c; + err = IOStream_write(stream, &b, 1); + if(err < 1){ + err = IOSTREAM_EOF; + } else { + err = b; + } + return err; +} + +/** Read from a stream, like fgetc(). + * + * @param stream to read from + * @return IOSTREAM_EOF on error, character read otherwise + */ +static inline int IOStream_getc(IOStream *stream){ + int err, rc; + unsigned char b; + + err = IOStream_read(stream, &b, 1); + if(err < 1){ + rc = IOSTREAM_EOF; + } else { + rc = b; + } + return rc; +} + +/** Get number of bytes read. + * + * @param stream to get from + * @return number of bytes read + */ +static inline int IOStream_get_read(IOStream *stream){ + return stream->read; +} + +/** Get number of bytes written. + * + * @param stream to get from + * @return number of bytes written + */ +static inline int IOStream_get_written(IOStream *stream){ + return stream->written; +} + + +#endif /* ! _XC_LINUX_SAVE_H_ */ diff --git a/tools/libxutil/kernel_stream.c b/tools/libxutil/kernel_stream.c new file mode 100644 index 0000000000..345b048015 --- /dev/null +++ b/tools/libxutil/kernel_stream.c @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2001 - 2004 Mike Wray + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** @file + * An IOStream implementation using printk() for output. + * Input is not implemented. + */ +#ifdef __KERNEL__ + +#include +#include +#include +#include +#include +#include +#include + +#include "kernel_stream.h" +#include "allocate.h" + +/** Number of characters in the output buffer. + * The kernel uses 1024 for printk, so that should suffice. + */ +#define BUF_N 1024 + +/** State for a kernel stream. */ +typedef struct KernelData { + /** Stream lock. We need a lock to serialize access to the stream. */ + spinlock_t lock; + /** Saved flags for locking. */ + unsigned long flags; + /** Size of the output buffer. */ + int buf_n; + /** Output buffer. */ + char buf[BUF_N]; +} KernelData; + +static int kernel_write(IOStream *s, const char *msg, int n); +static void kernel_free(IOStream *s); +static void kernel_stream_lock(IOStream *s); +static void kernel_stream_unlock(IOStream *s); + +/** Methods for a kernel stream. Output only. */ +static const IOMethods kernel_methods = { + write: kernel_write, + free: kernel_free, + lock: kernel_stream_lock, + unlock: kernel_stream_unlock, +}; + +/** Shared state for kernel streams. + * All implementations write using printk, so we can use + * shared state and avoid allocating it. + */ +static const KernelData kernel_data = { + lock: SPIN_LOCK_UNLOCKED, + flags: 0, + buf_n: BUF_N, +}; + +/** Stream for kernel printk. */ +static IOStream iokernel = { + methods: &kernel_methods, + data: &kernel_data, +}; + +/** Stream for kernel printk. */ +IOStream *iostdout = &iokernel; + +/** Stream for kernel printk. */ +IOStream *iostdin = &iokernel; + +/** Stream for kernel printk. */ +IOStream *iostderr = &iokernel; + +/** Get an output-only stream implementation using + * printk(). The stream uses static storage, and must not be freed. + * + * @return kernel stream + */ +IOStream get_stream_kernel(void){ + return iokernel; +} + +/** Obtain the lock on the stream state. + * + * @param kdata stream state + */ +static inline void KernelData_lock(KernelData *kdata){ + spin_lock_irqsave(&kdata->lock, kdata->flags); +} + +/** Release the lock on the stream state. + * + * @param kdata stream state + */ +static inline void KernelData_unlock(KernelData *kdata){ + spin_unlock_irqrestore(&kdata->lock, kdata->flags); +} + +/** Get the stream state. + * + * @param s kernel stream + * @return stream state + */ +static inline KernelData *get_kernel_data(IOStream *s){ + return (KernelData*)s->data; +} + +/** Obtain the lock on the stream state. + * + * @param s stream + */ +void kernel_stream_lock(IOStream *s){ + KernelData_lock(get_kernel_data(s)); +} + +/** Release the lock on the stream state. + * + * @param s stream + */ +void kernel_stream_unlock(IOStream *s){ + KernelData_unlock(get_kernel_data(s)); +} + +/** Write to a kernel stream. + * + * @param stream kernel stream + * @param format print format + * @param args print arguments + * @return result of the print + */ +static int kernel_write(IOStream *stream, const char *buf, int n){ + KernelData *kdata = get_kernel_data(stream); + int k; + k = kdata->buf_n - 1; + if(n < k) k = n; + memcpy(kdata->buf, buf, k); + kdata->buf[k] = '\0' + printk(kdata->buf); + return k; +} + +/** Free a kernel stream. + * Frees the internal state of the stream. + * Do not call this unless the stream was dynamically allocated. + * Do not call this on a stream returned from get_stream_kernel(). + * + * @param io stream to free + */ +static void kernel_free(IOStream *io){ + KernelData *kdata; + if(io == &iokernel) return; + kdata = get_kernel_data(io); + zero(kdata, sizeof(*kdata)); + deallocate(kdata); +} +#endif /* __KERNEL__ */ + + + + diff --git a/tools/libxutil/kernel_stream.h b/tools/libxutil/kernel_stream.h new file mode 100644 index 0000000000..be370f2a45 --- /dev/null +++ b/tools/libxutil/kernel_stream.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2001 - 2004 Mike Wray + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _XEN_LIB_KERNEL_STREAM_H_ +#define _XEN_LIB_KERNEL_STREAM_H_ + +#ifdef __KERNEL__ +#include "iostream.h" + +extern IOStream get_stream_kernel(void); +#define get_stream_stdout get_stream_kernel + +#endif /* __KERNEL__ */ +#endif /* !_XEN_LIB_KERNEL_STREAM_H_ */ diff --git a/tools/libxutil/lexis.c b/tools/libxutil/lexis.c new file mode 100644 index 0000000000..26d2ec4d5b --- /dev/null +++ b/tools/libxutil/lexis.c @@ -0,0 +1,93 @@ +/* + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of the + * License, or (at your option) any later version. This library is + * distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** @file + * Lexical analysis. + */ + +#include "sys_string.h" +#include "lexis.h" +#include + +/** Check if a value lies in a (closed) range. + * + * @param x value to test + * @param lo low end of the range + * @param hi high end of the range + * @return 1 if x is in the interval [lo, hi], 0 otherwise + */ +inline static int in_range(int x, int lo, int hi){ + return (lo <= x) && (x <= hi); +} + +/** Determine if a string is an (unsigned) decimal number. + * + * @param s pointer to characters to test + * @param n length of string + * @return 1 if s is a decimal number, 0 otherwise. + */ +int is_decimal_number(const char *s, int n){ + int i; + if(n <= 0)return 0; + for(i = 0; i < n; i++){ + if(!in_decimal_digit_class(s[i])) return 0; + } + return 1; +} + +/** Determine if a string is a hex number. + * Hex numbers are 0, or start with 0x or 0X followed + * by a non-zero number of hex digits (0-9,a-f,A-F). + * + * @param s pointer to characters to test + * @param n length of string + * @return 1 if s is a hex number, 0 otherwise. + */ +int is_hex_number(const char *s, int n){ + int i; + if(n <= 0) return 0; + if(n == 1){ + return s[0]=='0'; + } + if(n <= 3) return 0; + if(s[0] != '0' || (s[1] != 'x' && s[1] != 'X')) return 0; + for(i = 2; i < n; i++){ + if(!in_hex_digit_class(s[i])) return 0; + } + return 1; +} + +/** Test if a string matches a keyword. + * The comparison is case-insensitive. + * The comparison fails if either argument is null. + * + * @param s string + * @param k keyword + * @return 1 if they match, 0 otherwise + */ +int is_keyword(const char *s, const char *k){ + return s && k && !strcasecmp(s, k); +} + +/** Test if a string matches a character. + * + * @param s string + * @param c character (non-null) + * @return 1 if s contains exactly c, 0 otherwise + */ +int is_keychar(const char *s, char c){ + return c && (s[0] == c) && !s[1]; +} diff --git a/tools/libxutil/lexis.h b/tools/libxutil/lexis.h new file mode 100644 index 0000000000..7d8fe7bc63 --- /dev/null +++ b/tools/libxutil/lexis.h @@ -0,0 +1,122 @@ +/* + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of the + * License, or (at your option) any later version. This library is + * distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _SP_LEXIS_H_ +#define _SP_LEXIS_H_ + +#include "sys_string.h" +#include "sys_ctype.h" + +/** @file + * Lexical analysis. + */ + +/** Class of characters treated as space. */ +#define space_class ((char []){ '\n', '\r', '\t', ' ', '\f' , 0 }) + +/** Class of separator characters. */ +#define sep_class "{}()<>[]@!;" + +#define comment_class "#" + +/** Determine if a character is in a given class. + * + * @param c character to test + * @param s null-terminated string of characters in the class + * @return 1 if c is in the class, 0 otherwise. + */ +static inline int in_class(int c, const char *s){ + return s && (strchr(s, c) != 0); +} + +/** Determine if a character is in the space class. + * + * @param c character to test + * @return 1 if c is in the class, 0 otherwise. + */ +static inline int in_space_class(int c){ + return in_class(c, space_class); +} + +static inline int in_comment_class(int c){ + return in_class(c, comment_class); +} + +/** Determine if a character is in the separator class. + * Separator characters terminate tokens, and do not need space + * to separate them. + * + * @param c character to test + * @return 1 if c is in the class, 0 otherwise. + */ +static inline int in_sep_class(int c){ + return in_class(c, sep_class); +} + +/** Determine if a character is in the alpha class. + * + * @param c character to test + * @return 1 if c is in the class, 0 otherwise. + */ +static inline int in_alpha_class(int c){ + return isalpha(c); +} + +/** Determine if a character is in the octal digit class. + * + * @param c character to test + * @return 1 if c is in the class, 0 otherwise. + */ +static inline int in_octal_digit_class(int c){ + return '0' <= c && c <= '7'; +} + +/** Determine if a character is in the decimal digit class. + * + * @param c character to test + * @return 1 if c is in the class, 0 otherwise. + */ +static inline int in_decimal_digit_class(int c){ + return isdigit(c); +} + +/** Determine if a character is in the hex digit class. + * + * @param c character to test + * @return 1 if c is in the class, 0 otherwise. + */ +static inline int in_hex_digit_class(int c){ + return isdigit(c) || in_class(c, "abcdefABCDEF"); +} + + +static inline int in_string_quote_class(int c){ + return in_class(c, "'\""); +} + +static inline int in_printable_class(int c){ + return ('A' <= c && c <= 'Z') + || ('a' <= c && c <= 'z') + || ('0' <= c && c <= '9') + || in_class(c, "!$%&*+,-./:;<=>?@^_`{|}~"); +} + +extern int is_decimal_number(const char *s, int n); +extern int is_hex_number(const char *s, int n); +extern int is_keyword(const char *s, const char *k); +extern int is_keychar(const char *s, char c); + +#endif /* !_SP_LEXIS_H_ */ diff --git a/tools/libxutil/lzi_stream.c b/tools/libxutil/lzi_stream.c new file mode 100644 index 0000000000..0f09734201 --- /dev/null +++ b/tools/libxutil/lzi_stream.c @@ -0,0 +1,590 @@ +/* $Id: lzi_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $ */ +#define __FILE_ID_INFO "$Id: lzi_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $" +#include +static char __rcsid[] __attribute__((unused)) = WHAT_ID __FILE_ID_INFO; +/* + * Copyright (C) 2003 Hewlett-Packard Company. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** @file + * An IOStream implementation using LZI to provide compression and decompression. + * This is designed to provide compression without output latency. + * Flushing an LZI stream flushes all pending data to the underlying stream. + * This is essential for stream-based (e.g. networked) applications. + * + * A compressed data stream is a sequence of blocks. + * Each block is the block size followed by the compressed data. + * The last block has size zero. + * Sizes are 4-byte unsigned in network order. + * + * This format allows compressed data to be read from a stream without reading + * past the logical end of compressed data. + * + * @author Mike Wray + */ +#ifndef __KERNEL__ + +#include +#include +#include +#include + +#include "zlib.h" + +#include "allocate.h" +#include "lzi_stream.h" +#include "file_stream.h" +#include "marshal.h" + +#define dprintf(fmt, args...) fprintf(stdout, "[DEBUG] LZI>%s" fmt, __FUNCTION__, ##args) +#define wprintf(fmt, args...) fprintf(stderr, "[WARN] LZI>%s" fmt, __FUNCTION__, ##args) +#define iprintf(fmt, args...) fprintf(stdout, "[INFO] LZI>%s" fmt, __FUNCTION__, ##args) +#define eprintf(fmt, args...) fprintf(stderr, "[ERROR] LZI>%s" fmt, __FUNCTION__, ##args) + +static int lzi_read(IOStream *s, void *buf, size_t size, size_t count); +static int lzi_write(IOStream *s, const void *buf, size_t size, size_t count); +static int lzi_print(IOStream *s, const char *msg, va_list args); +static int lzi_getc(IOStream *s); +static int lzi_error(IOStream *s); +static int lzi_close(IOStream *s); +static void lzi_free(IOStream *s); +static int lzi_flush(IOStream *s); + +enum { + LZI_WRITE = 1, + LZI_READ = 2, +}; + +/** Methods used by a gzFile* IOStream. */ +static const IOMethods lzi_methods = { + read: lzi_read, + write: lzi_write, + print: lzi_print, + getc: lzi_getc, + error: lzi_error, + close: lzi_close, + free: lzi_free, + flush: lzi_flush, +}; + +#define BUFFER_SIZE (512 * 1024) + +typedef struct LZIState { + z_stream zstream; + void *inbuf; + uint32_t inbuf_size; + void *outbuf; + uint32_t outbuf_size; + /** Underlying stream for I/O. */ + IOStream *io; + /** Flags. */ + int flags; + /** Error indicator. */ + int error; + int eof; + int plain_bytes; + int comp_bytes; + int zstream_initialized; + int flushed; +} LZIState; + +static inline int LZIState_writeable(LZIState *s){ + return (s->flags & LZI_WRITE) != 0; +} + +static inline int LZIState_readable(LZIState *s){ + return (s->flags & LZI_READ) != 0; +} + +void LZIState_free(LZIState *z){ + if(!z) return; + if(z->zstream_initialized){ + if(LZIState_writeable(z)){ + deflateEnd(&z->zstream); + } else if(LZIState_readable(z)){ + inflateEnd(&z->zstream); + } + } + deallocate(z->inbuf); + deallocate(z->outbuf); + deallocate(z); +} + +static int mode_flags(const char *mode, int *flags){ + int err = 0; + int r=0, w=0; + if(!mode){ + err = -EINVAL; + goto exit; + } + for(; *mode; mode++){ + if(*mode == 'w') w = 1; + if(*mode == 'r') r = 1; + } + if(r + w != 1){ + err = -EINVAL; + goto exit; + } + if(r) *flags |= LZI_READ; + if(w) *flags |= LZI_WRITE; + exit: + return err; +} + +/** Get the stream state. + * + * @param s lzi stream + * @return stream state. + */ +static inline LZIState * lzi_state(IOStream *io){ + return io->data; +} + +IOStream *lzi_stream_io(IOStream *io){ + LZIState *s = lzi_state(io); + return s->io; +} + +static inline void set_error(LZIState *s, int err){ + if(err < 0 && !s->error){ + s->error = err; + } +} + +static int zerror(LZIState *s, int err){ + if(err){ + //dprintf("> err=%d\n", err); + if(err < 0) set_error(s, -EIO); + } + return s->error; +} + +int lzi_stream_plain_bytes(IOStream *io){ + LZIState *s = lzi_state(io); + return s->plain_bytes; +} + +int lzi_stream_comp_bytes(IOStream *io){ + LZIState *s = lzi_state(io); + return s->comp_bytes; +} + +float lzi_stream_ratio(IOStream *io){ + LZIState *s = lzi_state(io); + float ratio = 0.0; + if(s->comp_bytes){ + ratio = ((float) s->comp_bytes)/((float) s->plain_bytes); + } + return ratio; +} + +static int alloc(void **p, int n){ + *p = allocate(n); + return (p ? 0 : -ENOMEM); +} + +LZIState * LZIState_new(IOStream *io, int flags){ + int err = -ENOMEM; + int zlevel = Z_BEST_SPEED; // Level 1 compression - fastest. + int zstrategy = Z_DEFAULT_STRATEGY; + int zwindow = MAX_WBITS; + int zmemory = 8; + LZIState *z = ALLOCATE(LZIState); + + //dprintf(">\n"); + if(!z) goto exit; + z->io = io; + z->flags = flags; + + if(LZIState_writeable(z)){ + z->outbuf_size = BUFFER_SIZE; + /* windowBits is passed < 0 to suppress zlib header */ + err = deflateInit2(&z->zstream, zlevel, Z_DEFLATED, -zwindow, zmemory, zstrategy); + if (err != Z_OK) goto exit; + z->zstream_initialized = 1; + err = alloc(&z->outbuf, z->outbuf_size); + if(err) goto exit; + z->zstream.next_out = z->outbuf; + z->zstream.avail_out = z->outbuf_size; + } else { + z->inbuf_size = BUFFER_SIZE; + err = alloc(&z->inbuf, z->inbuf_size); + if(err) goto exit; + ///z->zstream.next_in = z->inbuf; + + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are + * present after the compressed stream. + */ + err = inflateInit2(&z->zstream, -zwindow); + if(err != Z_OK) goto exit; + z->zstream_initialized = 1; + } + + exit: + if(err){ + LZIState_free(z); + z = NULL; + } + //dprintf("< z=%p\n", z); + return z; +} + +int read_block(LZIState *s){ + int err = 0, k = 0; + //dprintf(">\n"); + if(s->eof) goto exit; + err = unmarshal_uint32(s->io, &k); + if(err) goto exit; + if(k > s->inbuf_size){ + err = -EINVAL; + goto exit; + } + if(k){ + err = unmarshal_bytes(s->io, s->inbuf, k); + if(err) goto exit; + } else { + s->eof = 1; + } + s->zstream.avail_in = k; + s->zstream.next_in = s->inbuf; + s->comp_bytes += 4; + s->comp_bytes += k; + exit: + //dprintf("< err=%d\n", err); + return err; +} + +int write_block(LZIState *s){ + int err = 0; + int k = ((char*)s->zstream.next_out) - ((char*)s->outbuf); + int k2 = s->outbuf_size - s->zstream.avail_out; + //dprintf("> k=%d k2=%d\n", k, k2); + if(!k) goto exit; + err = marshal_uint32(s->io, k); + if(err) goto exit; + err = marshal_bytes(s->io, s->outbuf, k); + if(err) goto exit; + s->zstream.next_out = s->outbuf; + s->zstream.avail_out = s->outbuf_size; + s->comp_bytes += 4; + s->comp_bytes += k; + exit: + //dprintf("< err=%d\n", err); + return err; +} + +int write_terminator(LZIState *s){ + int err = 0; + char c = 0; + err = marshal_uint32(s->io, 1); + if(err) goto exit; + err = marshal_bytes(s->io, &c, 1); + if(err) goto exit; + err = marshal_uint32(s->io, 0); + if(err) goto exit; + s->comp_bytes += 9; + exit: + return err; +} + +/** Write to the underlying stream using fwrite(); + * + * @param io destination + * @param buf data + * @param size size of data elements + * @param count number of data elements to write + * @return number of data elements written + */ +static int lzi_write(IOStream *io, const void *buf, size_t size, size_t count){ + int err = 0; + int n = size * count; + LZIState *s = lzi_state(io); + + //dprintf("> buf=%p size=%d count=%d n=%d\n", buf, size, count, n); + if(!LZIState_writeable(s)){ + err = -EINVAL; + goto exit; + } + s->flushed = 0; + s->zstream.next_in = (void*)buf; + s->zstream.avail_in = n; + while(s->zstream.avail_in){ + if(s->zstream.avail_out == 0){ + err = write_block(s); + if(err) goto exit; + } + //dprintf("> 1 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out); + //dprintf("> 1 deflate next_in=%p next_out=%p\n", s->zstream.next_in, s->zstream.next_out); + err = zerror(s, deflate(&s->zstream, Z_NO_FLUSH)); + //dprintf("> 2 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out); + //dprintf("> 2 deflate next_in=%p next_out=%p\n", s->zstream.next_in, s->zstream.next_out); + if(err) goto exit; + } + err = n; + s->plain_bytes += n; + if(size != 1) err /= size; + exit: + //dprintf("< err=%d\n", err); + return err; +} + + +/** Read from the underlying stream. + * + * @param io input + * @param buf where to put input + * @param size size of data elements + * @param count number of data elements to read + * @return number of data elements read + */ +static int lzi_read(IOStream *io, void *buf, size_t size, size_t count){ + int err, zerr; + int n = size * count; + LZIState *s = lzi_state(io); + + //dprintf("> size=%d count=%d n=%d\n", size, count, n); + if(!LZIState_readable(s)){ + err = -EINVAL; + goto exit; + } + s->zstream.next_out = buf; + s->zstream.avail_out = n; + while(s->zstream.avail_out){ + if(s->zstream.avail_in == 0){ + err = read_block(s); + } + //dprintf("> 1 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out); + zerr = inflate(&s->zstream, Z_NO_FLUSH); + //dprintf("> 2 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out); + if(zerr == Z_STREAM_END) break; + //dprintf("> zerr=%d\n", zerr); + err = zerror(s, zerr); + if(err) goto exit; + } + err = n - s->zstream.avail_out; + s->plain_bytes += err; + if(size != 1) err /= size; + exit: + set_error(s, err); + //dprintf("< err=%d\n", err); + return err; +} + +/** Print to the underlying stream. + * Returns 0 if the formatted output is too big for the internal buffer. + * + * @param io lzi stream + * @param msg format to use + * @param args arguments + * @return result of the print + */ +static int lzi_print(IOStream *io, const char *msg, va_list args){ + char buf[1024]; + int buf_n = sizeof(buf); + int n; + LZIState *s = lzi_state(io); + if(!LZIState_writeable(s)){ + n = -EINVAL; + goto exit; + } + n = vsnprintf(buf, buf_n, (char*)msg, args); + if(n < 0) goto exit; + if(n > buf_n){ + n = 0; + } else { + n = lzi_write(io, buf, 1, n); + } + exit: + return n; +} + +/** Read a character from the underlying stream + * + * @param io lzi stream + * @return character read, IOSTREAM_EOF on end of file (or error) + */ +static int lzi_getc(IOStream *io){ + int err; + char c; + err = lzi_read(io, &c, 1, 1); + if(err < 1) c = EOF; + err = (c==EOF ? IOSTREAM_EOF : c); + return err; +} + +static int flush_output(LZIState *s, int mode){ + int err = 0, zerr; + int done = 0; + int avail_out_old; + int count = 10; + + //dprintf("> avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out); + if(s->flushed == 1 + mode) goto exit; + //s->zstream.avail_in = 0; /* should be zero already anyway */ + for(;;){ + // Write any available output. + if(done || s->zstream.avail_out == 0){ + err = write_block(s); + if(err) goto exit; + if(done) break; + } + //dprintf("> 1 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out); + avail_out_old = s->zstream.avail_out; + zerr = deflate(&s->zstream, mode); + err = zerror(s, zerr); + //dprintf("> 2 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out); + //dprintf("> deflate=%d\n", err); + //done = (s->zstream.avail_out != 0); + //done = (s->zstream.avail_in == 0) && (s->zstream.avail_out == avail_out_old); + if(0 && mode == Z_FINISH){ + done = (zerr == Z_STREAM_END); + } else { + done = (s->zstream.avail_in == 0) + //&& (s->zstream.avail_out == avail_out_old) + && (s->zstream.avail_out != 0); + } + } + s->flushed = 1 + mode; + exit: + //dprintf("< err=%d\n", err); + return err; +} + +/** Flush any pending input to the underlying stream. + * + * @param s lzi stream + * @return 0 on success, error code otherwise + */ +static int lzi_flush(IOStream *io){ + int err = 0; + LZIState *s = lzi_state(io); + //dprintf(">\n"); + if(!LZIState_writeable(s)){ + err = -EINVAL; + goto exit; + } + err = flush_output(s, Z_SYNC_FLUSH); + if(err) goto exit; + err = IOStream_flush(s->io); + exit: + set_error(s, err); + //dprintf("< err=%d\n", err); + return (err < 0 ? err : 0); +} + +/** Check if a stream has an error. + * + * @param s lzi stream + * @return code if has an error, 0 otherwise + */ +static int lzi_error(IOStream *s){ + int err = 0; + LZIState *state = lzi_state(s); + err = state->error; + if(err) goto exit; + err = IOStream_error(state->io); + exit: + return err; +} + +/** Close an lzi stream. + * + * @param s lzi stream to close + * @return result of the close + */ +static int lzi_close(IOStream *io){ + int err = 0; + LZIState *s = lzi_state(io); + if(LZIState_writeable(s)){ + err = flush_output(s, Z_FINISH); + if(err) goto exit; + err = write_terminator(s); + if(err) goto exit; + err = IOStream_flush(s->io); + } + exit: + err = IOStream_close(s->io); + set_error(s, err); + return err; +} + +/** Free an lzi stream. + * + * @param s lzi stream + */ +static void lzi_free(IOStream *s){ + LZIState *state = lzi_state(s); + IOStream_free(state->io); + LZIState_free(state); + s->data = NULL; +} + +/** Create an lzi stream for an IOStream. + * + * @param io stream to wrap + * @return new IOStream using f for i/o + */ +IOStream *lzi_stream_new(IOStream *io, const char *mode){ + int err = -ENOMEM; + int flags = 0; + IOStream *zio = NULL; + LZIState *state = NULL; + + zio = ALLOCATE(IOStream); + if(!zio) goto exit; + err = mode_flags(mode, &flags); + if(err) goto exit; + state = LZIState_new(io, flags); + if(!state) goto exit; + err = 0; + zio->data = state; + zio->methods = &lzi_methods; + exit: + if(err){ + if(state) LZIState_free(state); + if(zio) deallocate(zio); + zio = NULL; + } + return zio; +} + +/** IOStream version of fdopen(). + * + * @param fd file descriptor + * @param flags giving the mode to open in (as for fdopen()) + * @return new stream for the open file, or NULL if failed + */ +IOStream *lzi_stream_fdopen(int fd, const char *mode){ + int err = -ENOMEM; + IOStream *io = NULL, *zio = NULL; + io = file_stream_fdopen(fd, mode); + if(!io) goto exit; + zio = lzi_stream_new(io, mode); + if(!io) goto exit; + err = 0; + exit: + if(err){ + IOStream_free(io); + IOStream_free(zio); + zio = NULL; + } + return zio; +} +#endif diff --git a/tools/libxutil/lzi_stream.h b/tools/libxutil/lzi_stream.h new file mode 100644 index 0000000000..0ad4f8db8e --- /dev/null +++ b/tools/libxutil/lzi_stream.h @@ -0,0 +1,36 @@ +#/* $Id: lzi_stream.h,v 1.3 2003/09/30 15:22:53 mjw Exp $ */ +/* + * Copyright (C) 2003 Hewlett-Packard Company. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _SP_LZI_STREAM_H_ +#define _SP_LZI_STREAM_H_ + +#ifndef __KERNEL__ +#include "iostream.h" + +extern IOStream *lzi_stream_new(IOStream *io, const char *mode); +extern IOStream *lzi_stream_fopen(const char *file, const char *mode); +extern IOStream *lzi_stream_fdopen(int fd, const char *mode); +extern IOStream *lzi_stream_io(IOStream *zio); + +extern int lzi_stream_plain_bytes(IOStream *io); +extern int lzi_stream_comp_bytes(IOStream *io); +extern float lzi_stream_ratio(IOStream *io); + +#endif +#endif /* !_SP_FILE_STREAM_H_ */ diff --git a/tools/libxutil/lzo_stream.c b/tools/libxutil/lzo_stream.c new file mode 100644 index 0000000000..bf7c348471 --- /dev/null +++ b/tools/libxutil/lzo_stream.c @@ -0,0 +1,596 @@ +/* $Id: lzo_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $ */ +#define __FILE_ID_INFO "$Id: lzo_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $" +#include +static char __rcsid[] __attribute__((unused)) = WHAT_ID __FILE_ID_INFO; +/* + * Copyright (C) 2003 Hewlett-Packard Company. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** @file + * An IOStream implementation using LZO to provide compression and decompression. + * This is designed to provide reasonable compression without output latency. + * Flushing an LZO stream flushes all pending data to the underlying stream. + * This is essential for stream-based (e.g. networked) applications. + * + * A compressed data stream is a sequence of blocks. + * Each block except the last is the plain data size followed by the compressed data size + * and the compressed data. The last block has plain data size zero and omits the rest. + * Sizes are 4-byte unsigned in network order. If the compressed size is smaller than + * the plain size the block data is compressed, otherwise it is plain (uncompressed). + * + * This format allows compressed data to be read from a stream without reading + * past the logical end of compressed data. + * + * @author Mike Wray + */ +#ifndef __KERNEL__ + +#include +#include +#include +#include + +#include "lzo1x.h" + +#include "allocate.h" +#include "lzo_stream.h" +#include "file_stream.h" +#include "marshal.h" + +#define dprintf(fmt, args...) fprintf(stdout, "[DEBUG] LZO>%s" fmt, __FUNCTION__, ##args) +#define wprintf(fmt, args...) fprintf(stderr, "[WARN] LZO>%s" fmt, __FUNCTION__, ##args) +#define iprintf(fmt, args...) fprintf(stdout, "[INFO] LZO>%s" fmt, __FUNCTION__, ##args) +#define eprintf(fmt, args...) fprintf(stderr, "[ERROR] LZO>%s" fmt, __FUNCTION__, ##args) + +static int lzo_read(IOStream *s, void *buf, size_t size, size_t count); +static int lzo_write(IOStream *s, const void *buf, size_t size, size_t count); +static int lzo_print(IOStream *s, const char *msg, va_list args); +static int lzo_getc(IOStream *s); +static int lzo_error(IOStream *s); +static int lzo_close(IOStream *s); +static void lzo_free(IOStream *s); +static int lzo_flush(IOStream *s); + +enum { + LZO_WRITE = 1, + LZO_READ = 2, +}; + +/** Methods used by a gzFile* IOStream. */ +static const IOMethods lzo_methods = { + read: lzo_read, + write: lzo_write, + print: lzo_print, + getc: lzo_getc, + error: lzo_error, + close: lzo_close, + free: lzo_free, + flush: lzo_flush, +}; + +//#define PLAIN_SIZE (64 * 1024) +//#define PLAIN_SIZE (128 * 1024) +#define PLAIN_SIZE (512 * 1024) + +//#define NOCOMPRESS + +typedef struct LZOState { + /** Flags. */ + int flags; + /** Error indicator. */ + int error; + /** Underlying stream for I/O. */ + IOStream *io; + /** Working memory (only needed for compression, not decompression). */ + lzo_byte *memory; + /** Buffer for plain (uncompressed) data. */ + lzo_byte *plain; + /** Size of the plain buffer. */ + lzo_uint plain_size; + /** Pointer into the plain buffer. */ + lzo_byte *plain_ptr; + /** Number of bytes of plain data available. */ + lzo_uint plain_n; + /** Buffer for compressed data. */ + lzo_byte *comp; + /** Size of the compressed buffer. */ + lzo_uint comp_size; + + int plain_bytes; + int comp_bytes; +} LZOState; + +void LZOState_free(LZOState *z){ + if(!z) return; + deallocate(z->memory); + deallocate(z->plain); + deallocate(z->comp); + deallocate(z); +} + +/** Maximum size of compressed data for the given plain data size. + * + * @param plain_size size of plain data + * @return maximum size of compressed data + */ +static int comp_size(int plain_size){ + return plain_size + (plain_size / 64) + 16 + 3; +} + +static int mode_flags(const char *mode, int *flags){ + int err = 0; + int r=0, w=0; + if(!mode){ + err = -EINVAL; + goto exit; + } + for(; *mode; mode++){ + if(*mode == 'w') w = 1; + if(*mode == 'r') r = 1; + } + if(r + w != 1){ + err = -EINVAL; + goto exit; + } + if(r) *flags |= LZO_READ; + if(w) *flags |= LZO_WRITE; + exit: + return err; +} + +/** Get the stream state. + * + * @param s lzo stream + * @return stream state. + */ +static inline LZOState * lzo_state(IOStream *s){ + return s->data; +} + +IOStream *lzo_stream_io(IOStream *s){ + LZOState *state = lzo_state(s); + return state->io; +} + +static inline void set_error(LZOState *state, int err){ + if(err < 0 && !state->error){ + state->error = err; + } +} + +int lzo_stream_plain_bytes(IOStream *s){ + LZOState *state = lzo_state(s); + return state->plain_bytes; +} + +int lzo_stream_comp_bytes(IOStream *s){ + LZOState *state = lzo_state(s); + return state->comp_bytes; +} + +float lzo_stream_ratio(IOStream *s){ + LZOState *state = lzo_state(s); + float ratio = 0.0; + if(state->comp_bytes){ + ratio = ((float) state->comp_bytes)/((float) state->plain_bytes); + } + return ratio; +} + +static inline int LZOState_writeable(LZOState *state){ + return (state->flags & LZO_WRITE) != 0; +} + +static inline int LZOState_readable(LZOState *state){ + return (state->flags & LZO_READ) != 0; +} + +LZOState * LZOState_new(IOStream *io, int flags){ + int err = -ENOMEM; + LZOState *z = ALLOCATE(LZOState); + //dprintf(">\n"); + if(!z) goto exit; + z->io = io; + z->flags = flags; + if(LZOState_writeable(z)){ + z->memory = allocate(LZO1X_1_MEM_COMPRESS); + if(!z->memory) goto exit; + } + z->plain_size = PLAIN_SIZE; + z->plain = allocate(z->plain_size); + if(!z->plain) goto exit; + z->plain_ptr = z->plain; + z->comp_size = comp_size(z->plain_size); + z->comp = allocate(z->comp_size); + if(!z->comp) goto exit; + err = 0; + exit: + if(err){ + LZOState_free(z); + z = NULL; + } + //dprintf("< z=%p\n", z); + return z; +} + +static int lzo_compress(LZOState *state){ + int err = 0; + int k, comp_n; + //dprintf(">\n"); + //dprintf(">plain=%p plain_n=%d comp=%p memory=%p\n", state->plain, state->plain_n, state->comp, state->memory); + // Compress the plain buffer. + err = lzo1x_1_compress(state->plain, state->plain_n, + state->comp, &comp_n, + state->memory); + //dprintf("> err=%d plain_n=%d comp_n=%d\n", err, state->plain_n, comp_n); + // Write plain size, compressed size. + err = marshal_uint32(state->io, state->plain_n); + if(err) goto exit; + err = marshal_uint32(state->io, comp_n); + if(err) goto exit; + //dprintf("> write data...\n"); + // Write the smaller of the compressed and plain data. + if(state->plain_n < comp_n){ + k = state->plain_n; + err = marshal_bytes(state->io, state->plain, state->plain_n); + } else { + k = comp_n; + err = marshal_bytes(state->io, state->comp, comp_n); + } + if(err) goto exit; + // Total output bytes. + k+= 8; + //dprintf("> wrote %d bytes\n", k); + state->plain_bytes += state->plain_n; + state->comp_bytes += k; + //dprintf("> plain=%d, comp=%d, ratio=%3.2f\n", + // state->plain_bytes, state->comp_bytes, + // ((float)state->comp_bytes)/((float)state->plain_bytes)); + // Reset the plain buffer. + state->plain_ptr = state->plain; + state->plain_n = 0; + err = k; + exit: + //dprintf("< err=%d\n", err); + return err; +} + +static int lzo_decompress(LZOState *state){ + int plain_n, comp_n; + int err, k; + //dprintf(">\n"); + err = unmarshal_uint32(state->io, &plain_n); + //dprintf("> err=%d plain_n=%d\n", err, plain_n); + if(err) goto exit; + state->comp_bytes += 4; + if(plain_n == 0) goto exit; + err = unmarshal_uint32(state->io, &comp_n); + //dprintf("> err=%d comp_n=%d\n", err, comp_n); + if(err) goto exit; + state->comp_bytes += 4; + if(plain_n > state->plain_size){ + err = -EINVAL; + goto exit; + } + if(comp_n > plain_n){ + //dprintf("> reading plain data %d...\n", plain_n); + k = plain_n; + err = unmarshal_bytes(state->io, state->plain, plain_n); + state->plain_n = plain_n; + } else { + //dprintf("> reading comp data %d...\n", comp_n); + k = comp_n; + err = unmarshal_bytes(state->io, state->comp, comp_n); + //dprintf("> decompress comp_n=%d\n", comp_n); + err = lzo1x_decompress(state->comp, comp_n, + state->plain, &state->plain_n, + state->memory); + //dprintf("> err=%d plain=%d state->plain_n=%d\n", err, plain_n, state->plain_n); + if(err != LZO_E_OK || state->plain_n != plain_n){ + // Bad. Corrupted input. + err = -EINVAL; + eprintf("> Corrupted!\n"); + goto exit; + } + } + state->comp_bytes += k; + state->plain_bytes += state->plain_n; + state->plain_ptr = state->plain; + err = k; + exit: + //dprintf("< err=%d\n", err); + return err; +} + +/** Write to the underlying stream using fwrite(); + * + * @param stream destination + * @param buf data + * @param size size of data elements + * @param count number of data elements to write + * @return number of data elements written + */ +static int lzo_write(IOStream *s, const void *buf, size_t size, size_t count){ + int err = 0; + int n = size * count; // Total number of bytes to write. + int chunk; // Size of chunk to write. + int remaining; // Number of bytes remaining to write. + int space; // Amount of space left in plain buffer. + LZOState *state = lzo_state(s); +#ifdef NOCOMPRESS + //dprintf("> buf=%p size=%d count=%d\n", buf, size, count); + err = IOStream_write(state->io, buf, size, count); + //dprintf("< err=%d\n", err); +#else + //dprintf("> buf=%p size=%d count=%d n=%d\n", buf, size, count, n); + remaining = n; + space = state->plain_size - state->plain_n; + //dprintf("> plain=%p plain_ptr=%p plain_n=%d space=%d\n", + // state->plain, state->plain_ptr, state->plain_n, space); + while(remaining){ + chunk = remaining; + if(chunk > space) chunk = space; + //dprintf("> memcpy %p %p %d\n", state->plain_ptr, buf, chunk); + memcpy(state->plain_ptr, buf, chunk); + remaining -= chunk; + space -= chunk; + state->plain_ptr += chunk; + state->plain_n += chunk; + if(space == 0){ + // Input buffer is full. Compress and write it. + err = lzo_compress(state); + if(err < 0) goto exit; + space = state->plain_size - state->plain_n; + } + } + err = (size > 1 ? n / size : n); + exit: + set_error(state, err); +#endif + return err; +} + + +/** Read from the underlying stream. + * + * @param stream input + * @param buf where to put input + * @param size size of data elements + * @param count number of data elements to read + * @return number of data elements read + */ +static int lzo_read(IOStream *s, void *buf, size_t size, size_t count){ + int err = 0; + int k = 0; // Number of (plain) bytes read. + int remaining = size * count; // Number of bytes remaining to read. + int chunk; // Size of chunk to read. + LZOState *state = lzo_state(s); +#ifdef NOCOMPRESS + //dprintf("> buf=%p size=%d count=%d\n", buf, size, count); + err = IOStream_read(state->io, buf, size, count); + //dprintf("< err=%d\n", err); +#else + if(!(state->flags & LZO_READ)){ + err = -EINVAL; + goto exit; + } + while(remaining){ + if(state->plain_n == 0){ + // No more plain input, decompress some more. + err = lzo_decompress(state); + if(err < 0) goto exit; + // Stop reading if there is no more input. + if(err == 0 || state->plain_n == 0) break; + } + chunk = remaining; + if(chunk > state->plain_n) chunk = state->plain_n; + memcpy(buf, state->plain_ptr, chunk); + k += chunk; + buf += chunk; + state->plain_ptr += chunk; + state->plain_n -= chunk; + remaining -= chunk; + } + err = k; + exit: + set_error(state, err); +#endif + return err; +} + +/** Print to the underlying stream. + * Returns 0 if the formatted output is too big for the internal buffer. + * + * @param s lzo stream + * @param msg format to use + * @param args arguments + * @return result of the print + */ +static int lzo_print(IOStream *s, const char *msg, va_list args){ + char buf[1024]; + int buf_n = sizeof(buf); + int n; + LZOState *state = lzo_state(s); + if(!LZOState_writeable(state)){ + n = -EINVAL; + goto exit; + } + n = vsnprintf(buf, buf_n, (char*)msg, args); + if(n < 0) goto exit; + if(n > buf_n){ + n = 0; + } else { + n = lzo_write(s, buf, 1, n); + } + exit: + return n; +} + +/** Read a character from the underlying stream + * + * @param s lzo stream + * @return character read, IOSTREAM_EOF on end of file (or error) + */ +static int lzo_getc(IOStream *s){ + int err; + char c; + err = lzo_read(s, &c, 1, 1); + if(err < 1) c = EOF; + err = (c==EOF ? IOSTREAM_EOF : c); + return err; +} + +/** Flush any pending input to the underlying stream. + * + * @param s lzo stream + * @return 0 on success, error code otherwise + */ +static int lzo_flush(IOStream *s){ + int err = 0; + LZOState *state = lzo_state(s); + //dprintf(">\n"); +#ifdef NOCOMPRESS + err = IOStream_flush(state->io); +#else + if(!LZOState_writeable(state)){ + err = -EINVAL; + goto exit; + } + if(state->plain_n){ + err = lzo_compress(state); + if(err < 0) goto exit; + } + err = IOStream_flush(state->io); + exit: + set_error(state, err); +#endif + //dprintf("< err=%d\n", err); + return (err < 0 ? err : 0); +} + +/** Check if a stream has an error. + * + * @param s lzo stream + * @return code if has an error, 0 otherwise + */ +static int lzo_error(IOStream *s){ + int err = 0; + LZOState *state = lzo_state(s); + err = state->error; + if(err) goto exit; + err = IOStream_error(state->io); + exit: + return err; +} + +int lzo_stream_finish(IOStream *s){ + int err = 0; + LZOState *state = lzo_state(s); + if(!LZOState_writeable(state)){ + err = -EINVAL; + goto exit; + } + err = lzo_flush(s); + if(err < 0) goto exit; + err = marshal_int32(state->io, 0); + exit: + return err; +} + +/** Close an lzo stream. + * + * @param s lzo stream to close + * @return result of the close + */ +static int lzo_close(IOStream *s){ + int err = 0; + LZOState *state = lzo_state(s); +#ifdef NOCOMPRESS + err = IOStream_close(state->io); +#else + if(LZOState_writeable(state)){ + err = lzo_stream_finish(s); + } + err = IOStream_close(state->io); + set_error(state, err); +#endif + return err; +} + +/** Free an lzo stream. + * + * @param s lzo stream + */ +static void lzo_free(IOStream *s){ + LZOState *state = lzo_state(s); + IOStream_free(state->io); + LZOState_free(state); + s->data = NULL; +} + +/** Create an lzo stream for an IOStream. + * + * @param io stream to wrap + * @return new IOStream using f for i/o + */ +IOStream *lzo_stream_new(IOStream *io, const char *mode){ + int err = -ENOMEM; + int flags = 0; + IOStream *zio = NULL; + LZOState *state = NULL; + + zio = ALLOCATE(IOStream); + if(!zio) goto exit; + err = mode_flags(mode, &flags); + if(err) goto exit; + state = LZOState_new(io, flags); + if(!state) goto exit; + err = 0; + zio->data = state; + zio->methods = &lzo_methods; + exit: + if(err){ + if(state) LZOState_free(state); + if(zio) deallocate(zio); + zio = NULL; + } + return zio; +} + +/** IOStream version of fdopen(). + * + * @param fd file descriptor + * @param flags giving the mode to open in (as for fdopen()) + * @return new stream for the open file, or NULL if failed + */ +IOStream *lzo_stream_fdopen(int fd, const char *mode){ + int err = -ENOMEM; + IOStream *io = NULL, *zio = NULL; + io = file_stream_fdopen(fd, mode); + if(!io) goto exit; + zio = lzo_stream_new(io, mode); + if(!io) goto exit; + err = 0; + exit: + if(err){ + IOStream_free(io); + IOStream_free(zio); + zio = NULL; + } + return zio; +} +#endif diff --git a/tools/libxutil/lzo_stream.h b/tools/libxutil/lzo_stream.h new file mode 100644 index 0000000000..493da7b1ad --- /dev/null +++ b/tools/libxutil/lzo_stream.h @@ -0,0 +1,36 @@ +#/* $Id: lzo_stream.h,v 1.3 2003/09/30 15:22:53 mjw Exp $ */ +/* + * Copyright (C) 2003 Hewlett-Packard Company. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _SP_LZO_STREAM_H_ +#define _SP_LZO_STREAM_H_ + +#ifndef __KERNEL__ +#include "iostream.h" + +extern IOStream *lzo_stream_new(IOStream *io, const char *mode); +extern IOStream *lzo_stream_fopen(const char *file, const char *mode); +extern IOStream *lzo_stream_fdopen(int fd, const char *mode); +extern IOStream *lzo_stream_io(IOStream *zio); + +extern int lzo_stream_plain_bytes(IOStream *io); +extern int lzo_stream_comp_bytes(IOStream *io); +extern float lzo_stream_ratio(IOStream *io); + +#endif +#endif /* !_SP_FILE_STREAM_H_ */ diff --git a/tools/libxutil/marshal.c b/tools/libxutil/marshal.c new file mode 100644 index 0000000000..21691d4412 --- /dev/null +++ b/tools/libxutil/marshal.c @@ -0,0 +1,207 @@ +#include +#include "sys_net.h" +#include "allocate.h" +#include "marshal.h" + +#define dprintf(fmt, args...) IOStream_print(iostdout, "[DEBUG] %s" fmt, __FUNCTION__, ##args) +#define wprintf(fmt, args...) IOStream_print(iostderr, "[WARN] %s" fmt, __FUNCTION__, ##args) +#define iprintf(fmt, args...) IOStream_print(iostdout, "[INFO] %s" fmt, __FUNCTION__, ##args) +#define eprintf(fmt, args...) IOStream_print(iostderr, "[ERROR] %s" fmt, __FUNCTION__, ##args) + + +#define ARRAY_SIZE(ary) (sizeof(ary)/sizeof((ary)[0])) + +/* Messages are coded as msgid followed by message fields. + * Initial message on any channel is hello - so can check version + * compatibility. + * + * char* -> uint16_t:n + * ints/uints go as suitable number of bytes (e.g. uint16_t is 2 bytes). + * optional fields go as '1' or '0' (the 0/1 is 1 byte). + * lists go as ('1' )* '0' + */ + +int marshal_flush(IOStream *io){ + int err = 0; + err = IOStream_flush(io); + return err; +} + +int marshal_bytes(IOStream *io, void *s, uint32_t s_n){ + int err = 0; + int n; + n = IOStream_write(io, s, s_n); + if(n < 0){ + err = n; + } else if (n < s_n){ + wprintf("> Wanted %d, got %d\n", s_n, n); + err = -EIO; + } + return err; +} + +int unmarshal_bytes(IOStream *io, void *s, uint32_t s_n){ + int err = 0; + int n; + //dprintf("> s_n=%d\n", s_n); + n = IOStream_read(io, s, s_n); + //dprintf("> n=%d\n", n); + if(n < 0){ + err = n; + } else if(n < s_n){ + wprintf("> Wanted %d, got %d\n", s_n, n); + err = -EIO; + } + //dprintf("< err=%d\n", err); + return err; +} + +int marshal_uint8(IOStream *io, uint8_t x){ + return marshal_bytes(io, &x, sizeof(x)); +} + +int unmarshal_uint8(IOStream *io, uint8_t *x){ + return unmarshal_bytes(io, x, sizeof(*x)); +} + +int marshal_uint16(IOStream *io, uint16_t x){ + x = htons(x); + return marshal_bytes(io, &x, sizeof(x)); +} + +int unmarshal_uint16(IOStream *io, uint16_t *x){ + int err = 0; + err = unmarshal_bytes(io, x, sizeof(*x)); + *x = ntohs(*x); + return err; +} + +int marshal_int32(IOStream *io, int32_t x){ + int err = 0; + //dprintf("> x=%d\n", x); + x = htonl(x); + err = marshal_bytes(io, &x, sizeof(x)); + //dprintf("< err=%d\n", err); + return err; +} + +int unmarshal_int32(IOStream *io, int32_t *x){ + int err = 0; + //dprintf(">\n"); + err = unmarshal_bytes(io, x, sizeof(*x)); + *x = ntohl(*x); + //dprintf("< err=%d x=%d\n", err, *x); + return err; +} + +int marshal_uint32(IOStream *io, uint32_t x){ + int err = 0; + //dprintf("> x=%u\n", x); + x = htonl(x); + err = marshal_bytes(io, &x, sizeof(x)); + //dprintf("< err=%d\n", err); + return err; +} + +int unmarshal_uint32(IOStream *io, uint32_t *x){ + int err = 0; + //dprintf(">\n"); + err = unmarshal_bytes(io, x, sizeof(*x)); + *x = ntohl(*x); + //dprintf("< err=%d x=%u\n", err, *x); + return err; +} + +int marshal_uint64(IOStream *io, uint64_t x){ + int err; + err = marshal_uint32(io, (uint32_t) ((x >> 32) & 0xffffffff)); + if(err) goto exit; + err = marshal_uint32(io, (uint32_t) ( x & 0xffffffff)); + exit: + return err; +} + +int unmarshal_uint64(IOStream *io, uint64_t *x){ + int err = 0; + uint32_t hi, lo; + err = unmarshal_uint32(io, &hi); + if(err) goto exit; + err = unmarshal_uint32(io, &lo); + *x = (((uint64_t) hi) << 32) | lo; + exit: + return err; +} + +int marshal_net16(IOStream *io, net16_t x){ + return marshal_bytes(io, &x, sizeof(x)); +} + +int unmarshal_net16(IOStream *io, net16_t *x){ + int err = 0; + err = unmarshal_bytes(io, x, sizeof(*x)); + return err; +} + +int marshal_net32(IOStream *io, net32_t x){ + return marshal_bytes(io, &x, sizeof(x)); +} + +int unmarshal_net32(IOStream *io, net32_t *x){ + int err = 0; + err = unmarshal_bytes(io, x, sizeof(*x)); + return err; +} + +int marshal_string(IOStream *io, char *s, uint32_t s_n){ + int err; + //dprintf("> s=%s\n", s); + err = marshal_uint32(io, s_n); + if(err) goto exit; + err = marshal_bytes(io, s, s_n); + exit: + //dprintf("< err=%d\n", err); + return err; +} + +int unmarshal_string(IOStream *io, char *s, uint32_t s_n){ + int err = 0, val_n = 0; + //dprintf(">\n"); + err = unmarshal_uint32(io, &val_n); + if(err) goto exit; + if(val_n >= s_n){ + err = -EINVAL; + goto exit; + } + err = unmarshal_bytes(io, s, val_n); + if(err) goto exit; + s[val_n] = '\0'; + exit: + //dprintf("< err=%d s=%s\n", err, s); + return err; +} + +int unmarshal_new_string(IOStream *io, char **s, uint32_t *s_n){ + int err = 0, val_n = 0; + char *val = NULL; + //dprintf(">\n"); + err = unmarshal_uint32(io, &val_n); + if(err) goto exit; + val = allocate(val_n + 1); + if(!val){ + err = -ENOMEM; + goto exit; + } + err = unmarshal_bytes(io, val, val_n); + if(err) goto exit; + val[val_n] = '\0'; + exit: + if(err){ + if(val) deallocate(val); + val = NULL; + val_n = 0; + } + *s = val; + if(s_n) *s_n = val_n; + //dprintf("< err=%d s=%s\n", err, *s); + return err; +} diff --git a/tools/libxutil/marshal.h b/tools/libxutil/marshal.h new file mode 100644 index 0000000000..9a9d465b9b --- /dev/null +++ b/tools/libxutil/marshal.h @@ -0,0 +1,43 @@ +/* $Id: marshal.h,v 1.1 2003/10/17 15:48:43 mjw Exp $ */ +#ifndef _SP_MARSHAL_H_ +#define _SP_MARSHAL_H_ + +#include "iostream.h" + +/** A 16-bit uint in network order, e.g. a port number. */ +typedef uint16_t net16_t; + +/** A 32-bit uint in network order, e.g. an IP address. */ +typedef uint32_t net32_t; + +extern int marshal_flush(IOStream *io); + +extern int marshal_bytes(IOStream *io, void *s, uint32_t s_n); +extern int unmarshal_bytes(IOStream *io, void *s, uint32_t s_n); + +extern int marshal_uint8(IOStream *io, uint8_t x); +extern int unmarshal_uint8(IOStream *io, uint8_t *x); + +extern int marshal_uint16(IOStream *io, uint16_t x); +extern int unmarshal_uint16(IOStream *io, uint16_t *x); + +extern int marshal_uint32(IOStream *io, uint32_t x); +extern int unmarshal_uint32(IOStream *io, uint32_t *x); + +extern int marshal_int32(IOStream *io, int32_t x); +extern int unmarshal_int32(IOStream *io, int32_t *x); + +extern int marshal_uint64(IOStream *io, uint64_t x); +extern int unmarshal_uint64(IOStream *io, uint64_t *x); + +extern int marshal_net16(IOStream *io, net16_t x); +extern int unmarshal_net16(IOStream *io, net16_t *x); + +extern int marshal_net32(IOStream *io, net32_t x); +extern int unmarshal_net32(IOStream *io, net32_t *x); + +extern int marshal_string(IOStream *io, char *s, uint32_t s_n); +extern int unmarshal_string(IOStream *io, char *s, uint32_t s_n); +extern int unmarshal_new_string(IOStream *io, char **s, uint32_t *s_n); + +#endif /* ! _SP_MARSHAL_H_ */ diff --git a/tools/libxutil/socket_stream.c b/tools/libxutil/socket_stream.c new file mode 100644 index 0000000000..cfa6e3abf0 --- /dev/null +++ b/tools/libxutil/socket_stream.c @@ -0,0 +1,259 @@ +/* $Id: socket_stream.c,v 1.9 2004/03/05 14:45:34 mjw Exp $ */ +/* + * Copyright (C) 2004 Mike Wray + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** @file + * An IOStream implementation using sockets. + */ + +#include +#include +#include +#include +#include +#include "allocate.h" +#include "socket_stream.h" + +#define MODULE_NAME "sock" +#define DEBUG 0 +//#undef DEBUG +#include "debug.h" + +static int socket_read(IOStream *s, void *buf, size_t n); +static int socket_write(IOStream *s, const void *buf, size_t n); +static int socket_error(IOStream *s); +static int socket_close(IOStream *s); +static void socket_free(IOStream *s); +static int socket_flush(IOStream *s); + +/** Methods used by a socket IOStream. */ +static const IOMethods socket_methods = { + read: socket_read, + write: socket_write, + error: socket_error, + close: socket_close, + free: socket_free, + flush: socket_flush, +}; + +/** Get the socket data. + * + * @param io socket stream + * @return data + */ +static inline SocketData * socket_data(IOStream *io){ + return (SocketData *)io->data; +} + +/** Test if a stream is a socket stream. + * + * @param io stream + * @return 0 if a socket stream, -EINVAL if not + */ +int socket_stream_check(IOStream *io){ + return (io && io->methods == &socket_methods ? 0 : -EINVAL); +} + +/** Get the data for a socket stream. + * + * @param io stream + * @param data return value for the data + * @return 0 if a socket stream, -EINVAL if not + */ +int socket_stream_data(IOStream *io, SocketData **data){ + int err = socket_stream_check(io); + if(err){ + *data = NULL; + } else { + *data = socket_data(io); + } + return err; +} + +/** Set the destination address for a socket stream. + * + * @param io stream + * @param addr address + * @return 0 if a socket stream, -EINVAL if not + */ +int socket_stream_set_addr(IOStream *io, struct sockaddr_in *addr){ + int err = 0; + SocketData *data = NULL; + err = socket_stream_data(io, &data); + if(!err){ + data->daddr = *addr; + } + return err; +} + +/** Set the send flags for a socket stream. + * + * @param io stream + * @param flags flags + * @return 0 if a socket stream, -EINVAL if not + */ +int socket_stream_set_flags(IOStream *io, int flags){ + int err = 0; + SocketData *data = NULL; + err = socket_stream_data(io, &data); + if(!err){ + data->flags = flags; + } + return err; +} + +/** Write to the underlying socket using sendto. + * + * @param stream input + * @param buf where to put input + * @param n number of bytes to write + * @return number of bytes written + */ +static int socket_write(IOStream *s, const void *buf, size_t n){ + SocketData *data = socket_data(s); + struct sockaddr *daddr = (struct sockaddr *)&data->daddr; + socklen_t daddr_n = sizeof(data->daddr); + int k; + dprintf("> sock=%d addr=%s:%d n=%d\n", + data->fd, inet_ntoa(data->daddr.sin_addr), ntohs(data->daddr.sin_port), n); + if(0){ + struct sockaddr_in self = {}; + socklen_t self_n; + getsockname(data->fd, (struct sockaddr *)&self, &self_n); + dprintf("> sockname sock=%d %s:%d\n", + data->fd, inet_ntoa(self.sin_addr), ntohs(self.sin_port)); + } + k = sendto(data->fd, buf, n, data->flags, daddr, daddr_n); + dprintf("> sendto=%d\n", k); + return k; +} + +/** Read from the underlying stream using recv(); + * + * @param stream input + * @param buf where to put input + * @param n number of bytes to read + * @return number of bytes read + */ +static int socket_read(IOStream *s, void *buf, size_t n){ + SocketData *data = socket_data(s); + int k; + struct sockaddr *saddr = (struct sockaddr *)&data->saddr; + socklen_t saddr_n = sizeof(data->saddr); + k = recvfrom(data->fd, buf, n, data->flags, saddr, &saddr_n); + return k; +} + +/** Print to the underlying socket. + * + * @param s socket stream + * @param msg format to use + * @param args arguments + * @return result of the print + */ +static int socket_print(IOStream *s, const char *msg, va_list args){ + SocketData *data = socket_data(s); + int n; + n = vsnprintf(data->buf, data->buf_n - 1, msg, args); + if(0 < n && n < data->buf_n){ + socket_write(s, data->buf, n); + } + return n; +} + +/** Read a character from the underlying socket + * + * @param s socket stream + * @return character read, IOSTREAM_EOF on end of socket (or error) + */ +static int socket_getc(IOStream *s){ + char b; + int n, c; + n = socket_read(s, &b, 1); + c = (n <= 0 ? IOSTREAM_EOF : b); + return c; +} + +/** Flush the socket (no-op). + * + * @param s socket stream + * @return 0 on success, error code otherwise + */ +static int socket_flush(IOStream *s){ + return 0; +} + +/** Check if a socket stream has an error (no-op). + * + * @param s socket stream + * @return 1 if has an error, 0 otherwise + */ +static int socket_error(IOStream *s){ + // Read SOL_SOCKET/SO_ERROR ? + return 0; +} + +/** Close a socket stream. + * + * @param s socket stream to close + * @return result of the close + */ +static int socket_close(IOStream *s){ + SocketData *data = socket_data(s); + return close(data->fd); +} + +/** Free a socket stream. + * + * @param s socket stream + */ +static void socket_free(IOStream *s){ + SocketData *data = socket_data(s); + deallocate(data); +} + +/** Create an IOStream for a socket. + * + * @param fd socket to wtap + * @return new IOStream using fd for i/o + */ +IOStream *socket_stream_new(int fd){ + int err = -ENOMEM; + IOStream *io = NULL; + SocketData *data = NULL; + + io = ALLOCATE(IOStream); + if(!io) goto exit; + io->methods = &socket_methods; + data = ALLOCATE(SocketData); + if(!data) goto exit; + io->data = data; + data->fd = fd; + data->buf_n = sizeof(data->buf); + err = 0; + exit: + if(err){ + if(io){ + if(data) deallocate(data); + deallocate(io); + io = NULL; + } + } + return io; +} + diff --git a/tools/libxutil/socket_stream.h b/tools/libxutil/socket_stream.h new file mode 100644 index 0000000000..5b8515f6b3 --- /dev/null +++ b/tools/libxutil/socket_stream.h @@ -0,0 +1,54 @@ +/* $Id: socket_stream.h,v 1.2 2004/03/04 17:38:13 mjw Exp $ */ +/* + * Copyright (C) 2004 Mike Wray + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _XEN_LIB_SOCKET_STREAM_H_ +#define _XEN_LIB_SOCKET_STREAM_H_ + +#ifndef __KERNEL__ +#include "iostream.h" +#include + +#include +#include +#include + +/** Data associated with a socket stream. */ +typedef struct SocketData { + /** The socket file descriptor. */ + int fd; + /** Source address from last read (recvfrom). */ + struct sockaddr_in saddr; + /** Destination address for writes (sendto). */ + struct sockaddr_in daddr; + /** Write flags (sendto). */ + int flags; + /** Buffer size. */ + int buf_n; + /** Buffer for formatted printing. */ + char buf[1024]; +} SocketData; + +extern IOStream *socket_stream_new(int fd); +extern int socket_stream_data(IOStream *io, SocketData **data); +extern int socket_stream_check(IOStream *io); +extern int socket_stream_set_addr(IOStream *io, struct sockaddr_in *addr); +extern int socket_stream_set_flags(IOStream *io, int flags); + +#endif +#endif /* !_XEN_LIB_SOCKET_STREAM_H_ */ diff --git a/tools/libxutil/string_stream.c b/tools/libxutil/string_stream.c new file mode 100644 index 0000000000..c3cf423d84 --- /dev/null +++ b/tools/libxutil/string_stream.c @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2001, 2002 Hewlett-Packard Company. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** @file + * IOStream subtype for input and output to strings. + * Usable from user or kernel code (with __KERNEL__ defined). + */ + +#include "sys_string.h" +#include "string_stream.h" +#include "allocate.h" + +static int string_print(IOStream *io, const char *msg, va_list args); +static int string_getc(IOStream *io); +static int string_error(IOStream *io); +static int string_close(IOStream *io); +static void string_free(IOStream *io); + +/** Methods for a string stream. */ +static IOMethods string_methods = { + //print: string_print, + //getc: string_getc, + error: string_error, + close: string_close, + free: string_free, +}; + +/** Get the string stream state. + * + * @param io string stream + * @return state + */ +static inline StringData *get_string_data(IOStream *io){ + return (StringData*)io->data; +} + +/** Read a character from a string stream. + * + * @param io string stream + * @return character read, IOSTREAM_EOF if no more input + */ +static int string_getc(IOStream *io){ + StringData *data = get_string_data(io); + int c = IOSTREAM_EOF; + char *s = data->in; + + if(s && s < data->end){ + c = (unsigned)*s; + data->in = s+1; + } + return c; +} + +/** Print to a string stream. + * Formats the data to an internal buffer and prints it. + * The formatted data must fit into the internal buffer. + * + * @param io string stream + * @param format print format + * @param args print arguments + * @return result of the print + */ +static int string_print(IOStream *io, const char *msg, va_list args){ + StringData *data = get_string_data(io); + int k = data->end - data->out; + int n = vsnprintf(data->out, k, (char*)msg, args); + if(n < 0 || n > k ){ + n = k; + IOStream_close(io); + } else { + data->out += n; + } + return n; +} + +/** Test if a string stream has an error. + * + * @param io string stream + * @return 0 if ok, error code otherwise + */ +static int string_error(IOStream *io){ + StringData *data = get_string_data(io); + return data->out == NULL; +} + +/** Close a string stream. + * + * @param io string stream + * @return 0 + */ +static int string_close(IOStream *io){ + StringData *data = get_string_data(io); + data->in = NULL; + data->out = NULL; + return 0; +} + +/** Free a string stream. + * The stream must have been allocated, not statically created. + * The stream state is freed, but the underlying string is not. + * + * @param io string stream + */ +static void string_free(IOStream *io){ + StringData *data = get_string_data(io); + zero(data, sizeof(*data)); + deallocate(data); +} + +/** Get the methods to use for a string stream. + * + * @return methods + */ +IOMethods *string_stream_get_methods(void){ + return &string_methods; +} + +/** Initialise a string stream, usually from static data. + * + * @param io address of IOStream to fill in + * @param data address of StringData to fill in + * @param s string to use + * @param n length of the string + */ +void string_stream_init(IOStream *io, StringData *data, char *s, int n){ + if(data && io){ + zero(data, sizeof(*data)); + data->string = (char*)s; + data->in = data->string; + data->out = data->string; + data->size = n; + data->end = data->string + n; + zero(io, sizeof(*io)); + io->methods = &string_methods; + io->data = data; + } +} + +/** Allocate and initialise a string stream. + * + * @param s string to use + * @param n length of the string + * @return new stream (free using IOStream_free) + */ +IOStream *string_stream_new(char *s, int n){ + int ok = 0; + StringData *data = ALLOCATE(StringData); + IOStream *io = ALLOCATE(IOStream); + if(data && io){ + ok = 1; + string_stream_init(io, data, s, n); + } + if(!ok){ + deallocate(data); + deallocate(io); + io = NULL; + } + return io; +} diff --git a/tools/libxutil/string_stream.h b/tools/libxutil/string_stream.h new file mode 100644 index 0000000000..36d764b265 --- /dev/null +++ b/tools/libxutil/string_stream.h @@ -0,0 +1,46 @@ +/* $Id: string_stream.h,v 1.1 2003/08/22 14:25:48 mjw Exp $ */ +/* + * Copyright (C) 2001, 2002 Hewlett-Packard Company. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _SP_STRING_STREAM_H_ +#define _SP_STRING_STREAM_H_ + +#include "iostream.h" + +/** Internal state for a string stream. + * Exposed here so that string streams can be statically created, using + * string_stream_init(). + */ +typedef struct { + /** The string used for input and ouput. */ + char *string; + /** Output pointer. */ + char *out; + /** Input pointer. */ + char *in; + /** Length of string. */ + int size; + /** End marker. */ + char *end; +} StringData; + +extern IOMethods *string_stream_get_methods(void); +extern IOStream *string_stream_new(char *s, int n); +extern void string_stream_init(IOStream *stream, StringData *data, char *s, int n); + +#endif /* !_SP_STRING_STREAM_H_ */ diff --git a/tools/libxutil/sxpr.c b/tools/libxutil/sxpr.c new file mode 100644 index 0000000000..adeffbe5eb --- /dev/null +++ b/tools/libxutil/sxpr.c @@ -0,0 +1,935 @@ +/* + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of the + * License, or (at your option) any later version. This library is + * distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include "sys_string.h" +#include "lexis.h" +#include "sys_net.h" +#include "hash_table.h" +#include "sxpr.h" + +#include +#undef free + +/** @file + * General representation of sxprs. + * Includes print, equal, and free functions for the sxpr types. + * + * Zero memory containing an Sxpr will have the value ONONE - this is intentional. + * When a function returning an sxpr cannot allocate memory we return ONOMEM. + * + */ + +static int atom_print(IOStream *io, Sxpr obj, unsigned flags); +static int atom_equal(Sxpr x, Sxpr y); +static void atom_free(Sxpr obj); + +static int string_print(IOStream *io, Sxpr obj, unsigned flags); +static int string_equal(Sxpr x, Sxpr y); +static void string_free(Sxpr obj); + +static int cons_print(IOStream *io, Sxpr obj, unsigned flags); +static int cons_equal(Sxpr x, Sxpr y); +static void cons_free(Sxpr obj); + +static int null_print(IOStream *io, Sxpr obj, unsigned flags); +static int none_print(IOStream *io, Sxpr obj, unsigned flags); +static int int_print(IOStream *io, Sxpr obj, unsigned flags); +static int bool_print(IOStream *io, Sxpr obj, unsigned flags); + +/** Type definitions. */ +static SxprType types[1024] = { + [T_NONE] { type: T_NONE, name: "none", print: none_print }, + [T_NULL] { type: T_NULL, name: "null", print: null_print }, + [T_UINT] { type: T_UINT, name: "int", print: int_print, }, + [T_BOOL] { type: T_BOOL, name: "bool", print: bool_print, }, + [T_ATOM] { type: T_ATOM, name: "atom", print: atom_print, + pointer: TRUE, + free: atom_free, + equal: atom_equal, + }, + [T_STRING] { type: T_STRING, name: "string", print: string_print, + pointer: TRUE, + free: string_free, + equal: string_equal, + }, + [T_CONS] { type: T_CONS, name: "cons", print: cons_print, + pointer: TRUE, + free: cons_free, + equal: cons_equal, + }, +}; + +/** Number of entries in the types array. */ +static int type_sup = sizeof(types)/sizeof(types[0]); + +/** Get the type definition for a given type code. + * + * @param ty type code + * @return type definition or null + */ +SxprType *get_sxpr_type(int ty){ + if(0 <= ty && ty < type_sup){ + return types+ty; + } + return NULL; +} + +/** The default print function. + * + * @param io stream to print to + * @param x sxpr to print + * @param flags print flags + * @return number of bytes written on success + */ +int default_print(IOStream *io, Sxpr x, unsigned flags){ + return IOStream_print(io, "#<%u %lu>\n", get_type(x), get_ul(x)); +} + +/** The default equal function. + * Uses eq(). + * + * @param x sxpr to compare + * @param y sxpr to compare + * @return 1 if equal, 0 otherwise + */ +int default_equal(Sxpr x, Sxpr y){ + return eq(x, y); +} + +/** General sxpr print function. + * Prints an sxpr on a stream using the print function for the sxpr type. + * Printing is controlled by flags from the PrintFlags enum. + * If PRINT_TYPE is in the flags the sxpr type is printed before the sxpr + * (for debugging). + * + * @param io stream to print to + * @param x sxpr to print + * @param flags print flags + * @return number of bytes written + */ +int objprint(IOStream *io, Sxpr x, unsigned flags){ + SxprType *def = get_sxpr_type(get_type(x)); + ObjPrintFn *print_fn = (def && def->print ? def->print : default_print); + int k = 0; + if(!io) return k; + if(flags & PRINT_TYPE){ + k += IOStream_print(io, "%s:", def->name); + } + k += print_fn(io, x, flags); + return k; +} + +/** General sxpr free function. + * Frees an sxpr using the free function for its type. + * Free functions must recursively free any subsxprs. + * If no function is defined then the default is to + * free sxprs whose type has pointer true. + * Sxprs must not be used after freeing. + * + * @param x sxpr to free + */ +void objfree(Sxpr x){ + SxprType *def = get_sxpr_type(get_type(x)); + + if(def){ + if(def->free){ + def->free(x); + } else if (def->pointer){ + hfree(x); + } + } +} + +/** General sxpr equality function. + * Compares x and y using the equal function for x. + * Uses default_equal() if x has no equal function. + * + * @param x sxpr to compare + * @param y sxpr to compare + * @return 1 if equal, 0 otherwise + */ +int objequal(Sxpr x, Sxpr y){ + SxprType *def = get_sxpr_type(get_type(x)); + ObjEqualFn *equal_fn = (def && def->equal ? def->equal : default_equal); + return equal_fn(x, y); +} + +/** Search for a key in an alist. + * An alist is a list of conses, where the cars + * of the conses are the keys. Compares keys using equality. + * + * @param k key + * @param l alist to search + * @return first element of l with car k, or ONULL + */ +Sxpr assoc(Sxpr k, Sxpr l){ + for( ; CONSP(l) ; l = CDR(l)){ + Sxpr x = CAR(l); + if(CONSP(x) && objequal(k, CAR(x))){ + return x; + } + } + return ONULL; +} + +/** Search for a key in an alist. + * An alist is a list of conses, where the cars + * of the conses are the keys. Compares keys using eq. + * + * @param k key + * @param l alist to search + * @return first element of l with car k, or ONULL + */ +Sxpr assocq(Sxpr k, Sxpr l){ + for( ; CONSP(l); l = CDR(l)){ + Sxpr x = CAR(l); + if(CONSP(x) && eq(k, CAR(x))){ + return x; + } + } + return ONULL; +} + +/** Add a new key and value to an alist. + * + * @param k key + * @param l value + * @param l alist + * @return l with the new cell added to the front + */ +Sxpr acons(Sxpr k, Sxpr v, Sxpr l){ + Sxpr x, y; + x = cons_new(k, v); + if(NOMEMP(x)) return x; + y = cons_new(x, l); + if(NOMEMP(y)) cons_free_cells(x); + return y; +} + +/** Test if a list contains an element. + * Uses sxpr equality. + * + * @param l list + * @param x element to look for + * @return a tail of l with x as car, or ONULL + */ +Sxpr cons_member(Sxpr l, Sxpr x){ + for( ; CONSP(l) && !eq(x, CAR(l)); l = CDR(l)){} + return l; +} + +/** Test if a list contains an element satisfying a test. + * The test function is called with v and an element of the list. + * + * @param l list + * @param test_fn test function to use + * @param v value for first argument to the test + * @return a tail of l with car satisfying the test, or 0 + */ +Sxpr cons_member_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v){ + for( ; CONSP(l) && !test_fn(v, CAR(l)); l = CDR(l)){ } + return l; +} + +/** Test if the elements of list 't' are a subset of the elements + * of list 's'. Element order is not significant. + * + * @param s element list to check subset of + * @param t element list to check if is a subset + * @return 1 if is a subset, 0 otherwise + */ +int cons_subset(Sxpr s, Sxpr t){ + for( ; CONSP(t); t = CDR(t)){ + if(!CONSP(cons_member(s, CAR(t)))){ + return 0; + } + } + return 1; +} + +/** Test if two lists have equal sets of elements. + * Element order is not significant. + * + * @param s list to check + * @param t list to check + * @return 1 if equal, 0 otherwise + */ +int cons_set_equal(Sxpr s, Sxpr t){ + return cons_subset(s, t) && cons_subset(t, s); +} + +#ifdef USE_GC +/*============================================================================*/ +/* The functions inside this ifdef are only safe if GC is used. + * Otherwise they may leak memory. + */ + +/** Remove an element from a list (GC only). + * Uses sxpr equality and removes all instances, even + * if there are more than one. + * + * @param l list to remove elements from + * @param x element to remove + * @return modified input list + */ +Sxpr cons_remove(Sxpr l, Sxpr x){ + return cons_remove_if(l, eq, x); +} + +/** Remove elements satisfying a test (GC only). + * The test function is called with v and an element of the set. + * + * @param l list to remove elements from + * @param test_fn function to use to decide if an element should be removed + * @return modified input list + */ +Sxpr cons_remove_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v){ + Sxpr prev = ONULL, elt, next; + + for(elt = l; CONSP(elt); elt = next){ + next = CDR(elt); + if(test_fn(v, CAR(elt))){ + if(NULLP(prev)){ + l = next; + } else { + CDR(prev) = next; + } + } + } + return l; +} + +/** Set the value for a key in an alist (GC only). + * If the key is present, changes the value, otherwise + * adds a new cell. + * + * @param k key + * @param v value + * @param l alist + * @return modified or extended list + */ +Sxpr setf(Sxpr k, Sxpr v, Sxpr l){ + Sxpr e = assoc(k, l); + if(NULLP(e)){ + l = acons(k, v, l); + } else { + CAR(CDR(e)) = v; + } + return l; +} +/*============================================================================*/ +#endif /* USE_GC */ + +/** Create a new atom with the given name. + * + * @param name the name + * @return new atom + */ +Sxpr atom_new(char *name){ + Sxpr n, obj = ONOMEM; + + n = string_new(name); + if(NOMEMP(n)) goto exit; + obj = HALLOC(ObjAtom, T_ATOM); + if(NOMEMP(obj)) goto exit; + OBJ_ATOM(obj)->name = n; + exit: + return obj; +} + +/** Free an atom. + * + * @param obj to free + */ +void atom_free(Sxpr obj){ + // Interned atoms are shared, so do not free. + if(OBJ_ATOM(obj)->interned) return; + objfree(OBJ_ATOM(obj)->name); + hfree(obj); +} + +/** Print an atom. Prints the atom name. + * + * @param io stream to print to + * @param obj to print + * @param flags print flags + * @return number of bytes printed + */ +int atom_print(IOStream *io, Sxpr obj, unsigned flags){ + //return string_print(io, OBJ_ATOM(obj)->name, (flags | PRINT_RAW)); + return string_print(io, OBJ_ATOM(obj)->name, flags); +} + +/** Atom equality. + * + * @param x to compare + * @param y to compare + * @return 1 if equal, 0 otherwise + */ +int atom_equal(Sxpr x, Sxpr y){ + int ok; + ok = eq(x, y); + if(ok) goto exit; + ok = ATOMP(y) && string_equal(OBJ_ATOM(x)->name, OBJ_ATOM(y)->name); + if(ok) goto exit; + ok = STRINGP(y) && string_equal(OBJ_ATOM(x)->name, y); + exit: + return ok; +} + +/** Get the name of an atom. + * + * @param obj atom + * @return name + */ +char * atom_name(Sxpr obj){ + return string_string(OBJ_ATOM(obj)->name); +} + +/** Get the C string from a string sxpr. + * + * @param obj string sxpr + * @return string + */ +char * string_string(Sxpr obj){ + return OBJ_STRING(obj); +} + +/** Get the length of a string. + * + * @param obj string + * @return length + */ +int string_length(Sxpr obj){ + return strlen(OBJ_STRING(obj)); +} + +/** Create a new string. The input string is copied, + * and must be null-terminated. + * + * @param s characters to put in the string + * @return new sxpr + */ +Sxpr string_new(char *s){ + int n = (s ? strlen(s) : 0); + Sxpr obj; + obj = halloc(n+1, T_STRING); + if(!NOMEMP(obj)){ + char *str = OBJ_STRING(obj); + strncpy(str, s, n); + str[n] = '\0'; + } + return obj; +} + +/** Free a string. + * + * @param obj to free + */ +void string_free(Sxpr obj){ + hfree(obj); +} + +/** Determine if a string needs escapes when printed + * using the given flags. + * + * @param str string to check + * @param flags print flags + * @return 1 if needs escapes, 0 otherwise + */ +int needs_escapes(char *str, unsigned flags){ + char *c; + int val = 0; + + if(str){ + for(c=str; *c; c++){ + if(in_alpha_class(*c)) continue; + if(in_decimal_digit_class(*c)) continue; + if(in_class(*c, "/._+:@~-")) continue; + val = 1; + break; + } + } + //printf("\n> val=%d str=|%s|\n", val, str); + return val; +} + +/** Print a string to a stream, with escapes if necessary. + * + * @param io stream to print to + * @param str string + * @param flags print flags + * @return number of bytes written + */ +int _string_print(IOStream *io, char *str, unsigned flags){ + int k = 0; + if((flags & PRINT_RAW) || !needs_escapes(str, flags)){ + k += IOStream_print(io, str); + } else { + k += IOStream_print(io, "\""); + if(str){ + char *s; + for(s = str; *s; s++){ + if(*s < ' ' || *s >= 127 ){ + switch(*s){ + case '\a': k += IOStream_print(io, "\\a"); break; + case '\b': k += IOStream_print(io, "\\b"); break; + case '\f': k += IOStream_print(io, "\\f"); break; + case '\n': k += IOStream_print(io, "\\n"); break; + case '\r': k += IOStream_print(io, "\\r"); break; + case '\t': k += IOStream_print(io, "\\t"); break; + case '\v': k += IOStream_print(io, "\\v"); break; + default: + // Octal escape; + k += IOStream_print(io, "\\%o", *s); + break; + } + } else if(*s == c_double_quote || + *s == c_single_quote || + *s == c_escape){ + k += IOStream_print(io, "\\%c", *s); + } else { + k+= IOStream_print(io, "%c", *s); + } + } + } + k += IOStream_print(io, "\""); + } + return k; +} + +/** Print a string to a stream, with escapes if necessary. + * + * @param io stream to print to + * @param obj string + * @param flags print flags + * @return number of bytes written + */ +int string_print(IOStream *io, Sxpr obj, unsigned flags){ + return _string_print(io, OBJ_STRING(obj), flags); +} + +/** Compare an sxpr with a string for equality. + * + * @param x string to compare with + * @param y sxpr to compare + * @return 1 if equal, 0 otherwise + */ +int string_equal(Sxpr x, Sxpr y){ + int ok = 0; + ok = eq(x,y); + if(ok) goto exit; + ok = has_type(y, T_STRING) && !strcmp(OBJ_STRING(x), OBJ_STRING(y)); + if(ok) goto exit; + ok = has_type(y, T_ATOM) && !strcmp(OBJ_STRING(x), atom_name(y)); + exit: + return ok; +} + +/** Create a new cons cell. + * The cell is ONOMEM if either argument is. + * + * @param car sxpr for the car + * @param cdr sxpr for the cdr + * @return new cons + */ +Sxpr cons_new(Sxpr car, Sxpr cdr){ + Sxpr obj; + if(NOMEMP(car) || NOMEMP(cdr)){ + obj = ONOMEM; + } else { + obj = HALLOC(ObjCons, T_CONS); + if(!NOMEMP(obj)){ + ObjCons *z = OBJ_CONS(obj); + z->car = car; + z->cdr = cdr; + } + } + return obj; +} + +/** Push a new element onto a list. + * + * @param list list to add to + * @param elt element to add + * @return 0 if successful, error code otherwise + */ +int cons_push(Sxpr *list, Sxpr elt){ + Sxpr l; + l = cons_new(elt, *list); + if(NOMEMP(l)) return -ENOMEM; + *list = l; + return 0; +} + +/** Free a cons. Recursively frees the car and cdr. + * + * @param obj to free + */ +void cons_free(Sxpr obj){ + Sxpr next; + for(; CONSP(obj); obj = next){ + next = CDR(obj); + objfree(CAR(obj)); + hfree(obj); + } + if(!NULLP(obj)){ + objfree(obj); + } +} + +/** Free a cons and its cdr cells, but not the car sxprs. + * Does nothing if called on something that is not a cons. + * + * @param obj to free + */ +void cons_free_cells(Sxpr obj){ + Sxpr next; + for(; CONSP(obj); obj = next){ + next = CDR(obj); + hfree(obj); + } +} + +/** Print a cons. + * Prints the cons in list format if the cdrs are conses. + * uses pair (dot) format if the last cdr is not a cons (or null). + * + * @param io stream to print to + * @param obj to print + * @param flags print flags + * @return number of bytes written + */ +int cons_print(IOStream *io, Sxpr obj, unsigned flags){ + int first = 1; + int k = 0; + k += IOStream_print(io, "("); + for( ; CONSP(obj) ; obj = CDR(obj)){ + if(first){ + first = 0; + } else { + k += IOStream_print(io, " "); + } + k += objprint(io, CAR(obj), flags); + } + if(!NULLP(obj)){ + k += IOStream_print(io, " . "); + k += objprint(io, obj, flags); + } + k += IOStream_print(io, ")"); + return (IOStream_error(io) ? -1 : k); +} + +/** Compare a cons with another sxpr for equality. + * If y is a cons, compares the cars and cdrs recursively. + * + * @param x cons to compare + * @param y sxpr to compare + * @return 1 if equal, 0 otherwise + */ +int cons_equal(Sxpr x, Sxpr y){ + return CONSP(y) && + objequal(CAR(x), CAR(y)) && + objequal(CDR(x), CDR(y)); +} + +/** Return the length of a cons list. + * + * @param obj list + * @return length + */ +int cons_length(Sxpr obj){ + int count = 0; + for( ; CONSP(obj); obj = CDR(obj)){ + count++; + } + return count; +} + +/** Destructively reverse a cons list in-place. + * If the argument is not a cons it is returned unchanged. + * + * @param l to reverse + * @return reversed list + */ +Sxpr nrev(Sxpr l){ + if(CONSP(l)){ + // Iterate down the cells in the list making the cdr of + // each cell point to the previous cell. The last cell + // is the head of the reversed list. + Sxpr prev = ONULL; + Sxpr cell = l; + Sxpr next; + + while(1){ + next = CDR(cell); + CDR(cell) = prev; + if(!CONSP(next)) break; + prev = cell; + cell = next; + } + l = cell; + } + return l; +} + +/** Print the null sxpr. + * + * @param io stream to print to + * @param obj to print + * @param flags print flags + * @return number of bytes written + */ +static int null_print(IOStream *io, Sxpr obj, unsigned flags){ + return IOStream_print(io, "()"); +} + +/** Print the `unspecified' sxpr none. + * + * @param io stream to print to + * @param obj to print + * @param flags print flags + * @return number of bytes written + */ +static int none_print(IOStream *io, Sxpr obj, unsigned flags){ + return IOStream_print(io, ""); +} + +/** Print an integer. + * + * @param io stream to print to + * @param obj to print + * @param flags print flags + * @return number of bytes written + */ +static int int_print(IOStream *io, Sxpr obj, unsigned flags){ + return IOStream_print(io, "%d", OBJ_INT(obj)); +} + +/** Print a boolean. + * + * @param io stream to print to + * @param obj to print + * @param flags print flags + * @return number of bytes written + */ +static int bool_print(IOStream *io, Sxpr obj, unsigned flags){ + return IOStream_print(io, (OBJ_UINT(obj) ? k_true : k_false)); +} + +int sxprp(Sxpr obj, Sxpr name){ + return CONSP(obj) && objequal(CAR(obj), name); +} + +/** Get the name of an element. + * + * @param obj element + * @return name + */ +Sxpr sxpr_name(Sxpr obj){ + Sxpr val = ONONE; + if(CONSP(obj)){ + val = CAR(obj); + } else if(STRINGP(obj) || ATOMP(obj)){ + val = obj; + } + return val; +} + +int sxpr_is(Sxpr obj, char *s){ + if(ATOMP(obj)) return !strcmp(atom_name(obj), s); + if(STRINGP(obj)) return !strcmp(string_string(obj), s); + return 0; +} + +int sxpr_elementp(Sxpr obj, Sxpr name){ + return CONSP(obj) && objequal(CAR(obj), name); +} + +/** Get the attributes of an sxpr. + * + * @param obj sxpr + * @return attributes + */ +Sxpr sxpr_attributes(Sxpr obj){ + Sxpr val = ONULL; + if(CONSP(obj)){ + obj = CDR(obj); + if(CONSP(obj)){ + obj = CAR(obj); + if(sxprp(obj, intern("@"))){ + val = CDR(obj); + } + } + } + return val; +} + +Sxpr sxpr_attribute(Sxpr obj, Sxpr key, Sxpr def){ + Sxpr val = ONONE; + val = assoc(sxpr_attributes(obj), key); + if(CONSP(val) && CONSP(CDR(val))){ + val = CADR(def); + } else { + val = def; + } + return val; +} + +/** Get the children of an sxpr. + * + * @param obj sxpr + * @return children + */ +Sxpr sxpr_children(Sxpr obj){ + Sxpr val = ONULL; + if(CONSP(obj)){ + val = CDR(obj); + if(CONSP(val) && sxprp(CAR(val), intern("@"))){ + val = CDR(val); + } + } + return val; +} + +Sxpr sxpr_child(Sxpr obj, Sxpr name, Sxpr def){ + Sxpr val = ONONE; + Sxpr l; + for(l = sxpr_children(obj); CONSP(l); l = CDR(l)){ + if(sxprp(CAR(l), name)){ + val = CAR(l); + break; + } + } + if(NONEP(val)) val = def; + return val; +} + +Sxpr sxpr_child0(Sxpr obj, Sxpr def){ + Sxpr val = ONONE; + Sxpr l = sxpr_children(obj); + if(CONSP(l)){ + val = CAR(l); + } else { + val = def; + } + return val; +} + +Sxpr sxpr_child_value(Sxpr obj, Sxpr name, Sxpr def){ + Sxpr val = ONONE; + val = sxpr_child(obj, name, ONONE); + if(NONEP(val)){ + val = def; + } else { + val = sxpr_child0(val, def); + } + return val; +} + +/** Table of interned symbols. Indexed by symbol name. */ +static HashTable *symbols = NULL; + +/** Hash function for entries in the symbol table. + * + * @param key to hash + * @return hashcode + */ +static Hashcode sym_hash_fn(void *key){ + return hash_string((char*)key); +} + +/** Key equality function for the symbol table. + * + * @param x to compare + * @param y to compare + * @return 1 if equal, 0 otherwise + */ +static int sym_equal_fn(void *x, void *y){ + return !strcmp((char*)x, (char*)y); +} + +/** Entry free function for the symbol table. + * + * @param table the entry is in + * @param entry being freed + */ +static void sym_free_fn(HashTable *table, HTEntry *entry){ + if(entry){ + objfree(((ObjAtom*)entry->value)->name); + HTEntry_free(entry); + } +} + +/** Initialize the symbol table. + * + * @return 0 on sucess, error code otherwise + */ +static int init_symbols(void){ + symbols = HashTable_new(100); + if(symbols){ + symbols->key_hash_fn = sym_hash_fn; + symbols->key_equal_fn = sym_equal_fn; + symbols->entry_free_fn = sym_free_fn; + return 0; + } + return -1; +} + +/** Cleanup the symbol table. Frees the table and all its symbols. + */ +void cleanup_symbols(void){ + HashTable_free(symbols); + symbols = NULL; +} + +/** Get the interned symbol with the given name. + * No new symbol is created. + * + * @return symbol or null + */ +Sxpr get_symbol(char *sym){ + HTEntry *entry; + if(!symbols){ + if(init_symbols()) return ONOMEM; + return ONULL; + } + entry = HashTable_get_entry(symbols, sym); + if(entry){ + return OBJP(T_ATOM, entry->value); + } else { + return ONULL; + } +} + +/** Get the interned symbol with the given name. + * Creates a new symbol if necessary. + * + * @return symbol + */ +Sxpr intern(char *sym){ + Sxpr symbol = get_symbol(sym); + if(NULLP(symbol)){ + if(!symbols) return ONOMEM; + symbol = atom_new(sym); + if(!NOMEMP(symbol)){ + OBJ_ATOM(symbol)->interned = TRUE; + HashTable_add(symbols, atom_name(symbol), get_ptr(symbol)); + } + } + return symbol; +} diff --git a/tools/libxutil/sxpr.h b/tools/libxutil/sxpr.h new file mode 100644 index 0000000000..b90083139c --- /dev/null +++ b/tools/libxutil/sxpr.h @@ -0,0 +1,413 @@ +/* + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of the + * License, or (at your option) any later version. This library is + * distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _XEN_LIB_SXPR_H_ +#define _XEN_LIB_SXPR_H_ + +#include + +#include "hash_table.h" +#include "iostream.h" +#include "allocate.h" + +/** @file + * Definitions for rules and sxprs. + */ + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +/** Sxpr type. */ +typedef int16_t TypeCode; + +/** A typed sxpr handle.*/ +typedef struct Sxpr { + /** Sxpr type. */ + TypeCode type; + union { + /** Sxpr value. */ + unsigned long ul; + /** Pointer. */ + void *ptr; + } v; +} Sxpr; + +/** Sxpr type to indicate out of memory. */ +#define T_NOMEM ((TypeCode)-1) +/** The 'unspecified' sxpr. */ +#define T_NONE ((TypeCode)0) +/** The empty list. */ +#define T_NULL ((TypeCode)1) +/** Unsigned integer. */ +#define T_UINT ((TypeCode)2) +/** A string. */ +#define T_STRING ((TypeCode)3) +/** An atom. */ +#define T_ATOM ((TypeCode)4) +/** A boolean. */ +#define T_BOOL ((TypeCode)5) + +/** A cons (pair or list). */ +#define T_CONS ((TypeCode)10) + +/** An error. */ +#define T_ERR ((TypeCode)40) + +/** An atom. */ +typedef struct ObjAtom { + Sxpr name; + Hashcode hashcode; + int interned; +} ObjAtom; + +/** A cons (pair). */ +typedef struct ObjCons { + Sxpr car; + Sxpr cdr; +} ObjCons; + +/** A vector. */ +typedef struct ObjVector { + int n; + Sxpr data[0]; +} ObjVector; + +/** Flags for sxpr printing. */ +enum PrintFlags { + PRINT_RAW = 0x001, + PRINT_TYPE = 0x002, + PRINT_PRETTY = 0x004, + PRINT_NUM = 0x008, +}; + +/** An integer sxpr. + * + * @param ty type + * @param val integer value + */ +#define OBJI(ty, val) (Sxpr){ type: (ty), v: { ul: (val) }} + +/** A pointer sxpr. + * If the pointer is non-null, returns an sxpr containing it. + * If the pointer is null, returns ONOMEM. + * + * @param ty type + * @param val pointer + */ +#define OBJP(ty, val) ((val) ? (Sxpr){ type: (ty), v: { ptr: (val) }} : ONOMEM) + +/** Make an integer sxpr containing a pointer. + * + * @param val pointer + */ +#define PTR(val) OBJP(T_UINT, (void*)(val)) + +/** Make an integer sxpr. + * @param x value + */ +#define OINT(x) OBJI(T_UINT, x) + +/** Make an error sxpr. + * + * @param x value + */ +#define OERR(x) OBJI(T_ERR, x) + +/** Out of memory constant. */ +#define ONOMEM OBJI(T_NOMEM, 0) + +/** The `unspecified' constant. */ +#define ONONE OBJI(T_NONE, 0) + +/** Empty list constant. */ +#define ONULL OBJI(T_NULL, 0) + +/** False constant. */ +#define OFALSE OBJI(T_BOOL, 0) + +/** True constant. */ +#define OTRUE OBJI(T_BOOL, 1) + +/* Recognizers for the various sxpr types. */ +#define ATOMP(obj) has_type(obj, T_ATOM) +#define BOOLP(obj) has_type(obj, T_BOOL) +#define CONSP(obj) has_type(obj, T_CONS) +#define ERRP(obj) has_type(obj, T_ERR) +#define INTP(obj) has_type(obj, T_UINT) +#define NOMEMP(obj) has_type(obj, T_NOMEM) +#define NONEP(obj) has_type(obj, T_NONE) +#define NULLP(obj) has_type(obj, T_NULL) +#define STRINGP(obj) has_type(obj, T_STRING) + +#define TRUEP(obj) get_ul(obj) + +/** Convert an sxpr to an unsigned integer. */ +#define OBJ_UINT(x) get_ul(x) +/** Convert an sxpr to an integer. */ +#define OBJ_INT(x) (int)get_ul(x) + +/* Conversions of sxprs to their values. + * No checking is done. + */ +#define OBJ_STRING(x) ((char*)get_ptr(x)) +#define OBJ_CONS(x) ((ObjCons*)get_ptr(x)) +#define OBJ_ATOM(x) ((ObjAtom*)get_ptr(x)) +#define OBJ_SET(x) ((ObjSet*)get_ptr(x)) +#define CAR(x) (OBJ_CONS(x)->car) +#define CDR(x) (OBJ_CONS(x)->cdr) + +#define CAAR(x) (CAR(CAR(x))) +#define CADR(x) (CAR(CDR(x))) +#define CDAR(x) (CDR(CAR(x))) +#define CDDR(x) (CDR(CDR(x))) + +/** Get the integer value from an sxpr. + * + * @param obj sxpr + * @return value + */ +static inline unsigned long get_ul(Sxpr obj){ + return obj.v.ul; +} + +/** Get the pointer value from an sxpr. + * + * @param obj sxpr + * @return value + */ +static inline void * get_ptr(Sxpr obj){ + return obj.v.ptr; +} + +/** Create an sxpr containing a pointer. + * + * @param type typecode + * @param val pointer + * @return sxpr + */ +static inline Sxpr obj_ptr(TypeCode type, void *val){ + return (Sxpr){ type: type, v: { ptr: val } }; +} + +/** Create an sxpr containing an integer. + * + * @param type typecode + * @param val integer + * @return sxpr + */ +static inline Sxpr obj_ul(TypeCode type, unsigned long val){ + return (Sxpr){ type: type, v: { ul: val } }; +} + +/** Get the type of an sxpr. + * + * @param obj sxpr + * @return type + */ +static inline TypeCode get_type(Sxpr obj){ + return obj.type; +} + +/** Check the type of an sxpr. + * + * @param obj sxpr + * @param type to check + * @return 1 if has the type, 0 otherwise + */ +static inline int has_type(Sxpr obj, TypeCode type){ + return get_type(obj) == type; +} + +/** Compare sxprs for literal equality of type and value. + * + * @param x sxpr to compare + * @param y sxpr to compare + * @return 1 if equal, 0 otherwise + */ +static inline int eq(Sxpr x, Sxpr y){ + return ((get_type(x) == get_type(y)) && (get_ul(x) == get_ul(y))); +} + +/** Checked version of CAR + * + * @param x sxpr + * @return CAR if a cons, x otherwise + */ +static inline Sxpr car(Sxpr x){ + return (CONSP(x) ? CAR(x) : x); +} + +/** Checked version of CDR. + * + * @param x sxpr + * @return CDR if a cons, null otherwise + */ +static inline Sxpr cdr(Sxpr x){ + return (CONSP(x) ? CDR(x) : ONULL); +} + +/** Allocate some memory and return an sxpr containing it. + * Returns ONOMEM if allocation failed. + * + * @param n number of bytes to allocate + * @param ty typecode + * @return sxpr + */ +static inline Sxpr halloc(size_t n, TypeCode ty){ + return OBJP(ty, allocate(n)); +} + +/** Allocate an sxpr containing a pointer to the given type. + * + * @param ty type (uses sizeof to determine how many bytes to allocate) + * @param code typecode + * @return sxpr, ONOMEM if allocation failed + */ +#define HALLOC(ty, code) halloc(sizeof(ty), code) + +typedef int ObjPrintFn(IOStream *io, Sxpr obj, unsigned flags); +typedef int ObjEqualFn(Sxpr obj, Sxpr other); +typedef void ObjFreeFn(Sxpr obj); + +/** An sxpr type definition. */ +typedef struct SxprType { + TypeCode type; + char *name; + int pointer; + ObjPrintFn *print; + ObjEqualFn *equal; + ObjFreeFn *free; +} SxprType; + + +extern SxprType *get_sxpr_type(int ty); + +/** Free the pointer in an sxpr. + * + * @param x sxpr containing a pointer + */ +static inline void hfree(Sxpr x){ + deallocate(get_ptr(x)); +} + +extern int objprint(IOStream *io, Sxpr x, unsigned flags); +extern int objequal(Sxpr x, Sxpr y); +extern void objfree(Sxpr x); + +extern void cons_free_cells(Sxpr obj); +extern Sxpr intern(char *s); + +extern Sxpr assoc(Sxpr k, Sxpr l); +extern Sxpr assocq(Sxpr k, Sxpr l); +extern Sxpr acons(Sxpr k, Sxpr v, Sxpr l); +extern Sxpr nrev(Sxpr l); +extern Sxpr cons_member(Sxpr l, Sxpr x); +extern Sxpr cons_member_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v); +extern int cons_subset(Sxpr s, Sxpr t); +extern int cons_set_equal(Sxpr s, Sxpr t); + +#ifdef USE_GC +extern Sxpr cons_remove(Sxpr l, Sxpr x); +extern Sxpr cons_remove_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v); +#endif + +extern Sxpr atom_new(char *name); +extern char * atom_name(Sxpr obj); + +extern Sxpr string_new(char *s); +extern char * string_string(Sxpr obj); +extern int string_length(Sxpr obj); + +extern Sxpr cons_new(Sxpr car, Sxpr cdr); +extern int cons_push(Sxpr *list, Sxpr elt); +extern int cons_length(Sxpr obj); + +Sxpr sxpr_name(Sxpr obj); +int sxpr_is(Sxpr obj, char *s); +int sxpr_elementp(Sxpr obj, Sxpr name); +Sxpr sxpr_attributes(Sxpr obj); +Sxpr sxpr_attribute(Sxpr obj, Sxpr key, Sxpr def); +Sxpr sxpr_children(Sxpr obj); +Sxpr sxpr_child(Sxpr obj, Sxpr name, Sxpr def); +Sxpr sxpr_child0(Sxpr obj, Sxpr def); +Sxpr sxpr_child_value(Sxpr obj, Sxpr name, Sxpr def); + +/** Create a new atom. + * + * @param s atom name + * @return new atom + */ +static inline Sxpr mkatom(char *s){ + return atom_new(s); +} + +/** Create a new string sxpr. + * + * @param s string bytes (copied) + * @return new string + */ +static inline Sxpr mkstring(char *s){ + return string_new(s); +} + +/** Create an integer sxpr. + * + * @param i value + * @return sxpr + */ +static inline Sxpr mkint(int i){ + return OBJI(T_UINT, i); +} + +/** Create a boolean sxpr. + * + * @param b value + * @return sxpr + */ +static inline Sxpr mkbool(int b){ + return OBJI(T_BOOL, (b ? 1 : 0)); +} + +/* Constants used in parsing and printing. */ +#define k_list_open "(" +#define c_list_open '(' +#define k_list_close ")" +#define c_list_close ')' +#define k_true "true" +#define k_false "false" + +#define c_var '$' +#define c_escape '\\' +#define c_single_quote '\'' +#define c_double_quote '"' +#define c_string_open c_double_quote +#define c_string_close c_double_quote +#define c_data_open '[' +#define c_data_close ']' +#define c_binary '*' +#define c_eval '!' +#define c_concat_open '{' +#define c_concat_close '}' + +#endif /* ! _XEN_LIB_SXPR_H_ */ diff --git a/tools/libxutil/sxpr_parser.c b/tools/libxutil/sxpr_parser.c new file mode 100644 index 0000000000..16fec56b67 --- /dev/null +++ b/tools/libxutil/sxpr_parser.c @@ -0,0 +1,897 @@ + +#ifdef __KERNEL__ +# include +# include +# include +# include +# include +#else +# include +# include +#endif + +#include "iostream.h" +#include "lexis.h" +#include "sxpr_parser.h" +#include "sys_string.h" + +/** @file + * Sxpr parsing. + * + * So that the parser does not leak memory, all sxprs constructed by + * the parser must be freed on error. On successful parse the sxpr + * returned becomes the responsibility of the caller. + * + * @author Mike Wray + */ + +#define dprintf(fmt, args...) IOStream_print(iostdout, "[DEBUG] %s" fmt, __FUNCTION__, ##args) +#define printf(fmt, args...) IOStream_print(iostdout, fmt, ##args) + +static void reset(Parser *z); +static int inputchar(Parser *p, char c); +static int savechar(Parser *p, char c); +extern void parse_error(Parser *in); +extern void parse_error_id(Parser *in, ParseErrorId id); + +static int begin_start(Parser *p, char c); +static int state_start(Parser *p, char c); +static int end_start(Parser *p); + +static int begin_comment(Parser *p, char c); +static int state_comment(Parser *p, char c); +static int end_comment(Parser *p); + +static int begin_string(Parser *p, char c); +static int state_string(Parser *p, char c); +static int end_string(Parser *p); +static int state_escape(Parser *p, char c); +static int state_octal(Parser *p, char c); +static int state_hex(Parser *p, char c); + +static int begin_atom(Parser *p, char c); +static int state_atom(Parser *p, char c); +static int end_atom(Parser *p); + +static int state_list(Parser *p, char c); +static int begin_list(Parser *p, char c); +static int end_list(Parser *p); + +/** Print a parse error. + * + * @param in parser + * @param msg format followed by printf arguments + */ +void eprintf(Parser *in, char *msg, ...){ + va_list args; + if(in->error_out){ + va_start(args, msg); + IOStream_vprint(in->error_out, msg, args); + va_end(args); + } +} + +/** Print a parse warning. + * + * @param in parser + * @param msg format followed by printf arguments + */ +void wprintf(Parser *in, char *msg, ...){ + va_list args; + if(in->error_out){ + va_start(args, msg); + IOStream_vprint(in->error_out, msg, args); + va_end(args); + } +} + +/*============================================================================*/ + +/** Record defining the message for a parse error. */ +typedef struct { + ParseErrorId id; + char *message; +} ParseError; + +/** Format for printing parse error messages. */ +#define PARSE_ERR_FMT "parse error> line %3d, column %2d: %s" + +/** Message catalog for the parse error codes. */ +static ParseError catalog[] = { + { PARSE_ERR_UNSPECIFIED, "unspecified error" }, + { PARSE_ERR_NOMEM, "out of memory" }, + { PARSE_ERR_UNEXPECTED_EOF, "unexpected end of input" }, + { PARSE_ERR_TOKEN_TOO_LONG, "token too long" }, + { PARSE_ERR_INVALID_SYNTAX, "syntax error" }, + { PARSE_ERR_INVALID_ESCAPE, "invalid escape" }, + { 0, NULL } +}; + +/** Number of entries in the message catalog. */ +const static int catalog_n = sizeof(catalog)/sizeof(ParseError); + +void ParserState_free(ParserState *z){ + if(!z) return; + objfree(z->val); + deallocate(z); +} + +int ParserState_new(ParserStateFn *fn, ParserState *parent, ParserState **val){ + int err = 0; + ParserState *z; + z = ALLOCATE(ParserState); + if(z){ + z->fn = fn; + z->parent = parent; + z->val = ONULL; + } else { + err = -ENOMEM; + } + if(!err) *val = z; + return err; +} + +/** Free a parser. + * No-op if the parser is null. + * + * @param z parser + */ +void Parser_free(Parser *z){ + if(!z) return; + objfree(z->val); + z->val = ONONE; + deallocate(z); +} + +/** Create a new parser. The error stream defaults to null. + */ +Parser * Parser_new(void){ + Parser *z = ALLOCATE(Parser); + int err = -ENOMEM; + + if(!z) goto exit; + err = 0; + reset(z); + exit: + if(err){ + Parser_free(z); + z = NULL; + } + return z; +} + +/** Get the next character. + * Records the character read in the parser, + * and sets the line and character counts. + * + * @param p parser + * @return error flag: 0 on success, non-zero on error + */ +static int inputchar(Parser *p, char c){ + int err = 0; + if(c=='\n'){ + p->line_no++; + p->char_no = 0; + } else { + p->char_no++; + } + return err; +} + +static int savechar(Parser *p, char c){ + int err = 0; + if(p->buf_i >= p->buf_n){ + err = -ENOMEM; + goto exit; + } + p->buf[p->buf_i] = c; + p->buf_i++; + exit: + return err; +} + +int Parser_input_char(Parser *p, char c){ + int err = 0; + if(at_eof(p)){ + //skip; + } else { + inputchar(p, c); + } + if(!p->state){ + err = begin_start(p, c); + if(err) goto exit; + } + err = p->state->fn(p, c); + exit: + return err; +} + +int Parser_input_eof(Parser *p){ + int err = 0; + p->eof = 1; + err = Parser_input_char(p, IOSTREAM_EOF); + return err; +} + +int Parser_input(Parser *p, char *buf, int buf_n){ + int err = 0; + int i = 0; + if(buf_n <= 0){ + err = Parser_input_eof(p); + goto exit; + } + for(i = 0; istate, &p->state); + return err; +} + +int Parser_pop(Parser *p){ + int err = 0; + ParserState *s = p->state; + p->state = s->parent; + ParserState_free(s); + return err; +} + +int Parser_return(Parser *p){ + int err = 0; + Sxpr val = ONONE; + if(!p->state){ + err = -EINVAL; + goto exit; + } + val = p->state->val; + p->state->val = ONONE; + err = Parser_pop(p); + if(err) goto exit; + if(p->state){ + err = cons_push(&p->state->val, val); + } else { + val = nrev(val); + p->val = val; + } + exit: + if(err){ + objfree(val); + } + return err; +} + +/** Determine if a character is a separator. + * + * @param p parser + * @param c character to test + * @return 1 if a separator, 0 otherwise + */ +static int is_separator(Parser *p, char c){ + return in_sep_class(c); +} + +/** Return the current token. + * The return value points at the internal buffer, so + * it must not be modified (or freed). Use copy_token() if you need a copy. + * + * @param p parser + * @return token + */ +char *peek_token(Parser *p){ + return p->buf; +} + +/** Return a copy of the current token. + * The returned value should be freed when finished with. + * + * @param p parser + * @return copy of token + */ +char *copy_token(Parser *p){ + return strdup(peek_token(p)); +} + +static int do_intern(Parser *p){ + int err = 0; + Sxpr obj = intern(peek_token(p)); + if(NOMEMP(obj)){ + err = -ENOMEM; + } else { + p->state->val = obj; + } + return err; +} + +static int do_string(Parser *p){ + int err = 0; + Sxpr obj; + obj = string_new(peek_token(p)); + if(NOMEMP(obj)){ + err = -ENOMEM; + } else { + p->state->val = obj; + } + return err; +} + +void newtoken(Parser *p){ + memset(p->buf, 0, p->buf_n); + p->buf_i = 0; + p->tok_begin_line = p->line_no; + p->tok_begin_char = p->char_no; +} + +int get_escape(char c, char *d){ + int err = 0; + switch(c){ + case 'a': *d = '\a'; break; + case 'b': *d = '\b'; break; + case 'f': *d = '\f'; break; + case 'n': *d = '\n'; break; + case 'r': *d = '\r'; break; + case 't': *d = '\t'; break; + case 'v': *d = '\v'; break; + case c_escape: *d = c_escape; break; + case c_single_quote: *d = c_single_quote; break; + case c_double_quote: *d = c_double_quote; break; + default: + err = -EINVAL; + } + return err; +} + + +int begin_start(Parser *p, char c){ + return Parser_push(p, state_start); +} + +int state_start(Parser *p, char c){ + int err = 0; + if(at_eof(p)){ + err = end_start(p); + } else if(in_space_class(c)){ + //skip + } else if(in_comment_class(c)){ + begin_comment(p, c); + } else if(c == c_list_open){ + begin_list(p, c); + } else if(c == c_list_close){ + parse_error(p); + err = -EINVAL; + } else if(in_string_quote_class(c)){ + begin_string(p, c); + } else if(in_printable_class(c)){ + begin_atom(p, c); + } else if(c == 0x04){ + //ctrl-D, EOT: end-of-text. + Parser_input_eof(p); + } else { + parse_error(p); + err = -EINVAL; + } + return err; +} + +int end_start(Parser *p){ + int err = 0; + err = Parser_return(p); + return err; +} + +int begin_comment(Parser *p, char c){ + int err = 0; + err = Parser_push(p, state_comment); + if(err) goto exit; + err = inputchar(p, c); + exit: + return err; +} + +int state_comment(Parser *p, char c){ + int err = 0; + if(c == '\n' || at_eof(p)){ + err = end_comment(p); + } else { + err = inputchar(p, c); + } + return err; +} + +int end_comment(Parser *p){ + return Parser_pop(p); +} + +int begin_string(Parser *p, char c){ + int err = 0; + err = Parser_push(p, state_string); + if(err) goto exit; + newtoken(p); + p->state->delim = c; + exit: + return err; +} + +int state_string(Parser *p, char c){ + int err = 0; + if(at_eof(p)){ + parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF); + err = -EINVAL; + } else if(c == p->state->delim){ + err = end_string(p); + } else if(c == '\\'){ + err = Parser_push(p, state_escape); + } else { + err = savechar(p, c); + } + return err; +} + +int end_string(Parser *p){ + int err = 0; + err = do_string(p); + if(err) goto exit; + err = Parser_return(p); + exit: + return err; +} + +int state_escape(Parser *p, char c){ + int err = 0; + char d; + if(at_eof(p)){ + parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF); + err = -EINVAL; + goto exit; + } + if(get_escape(c, &d) == 0){ + err = savechar(p, d); + if(err) goto exit; + err = Parser_pop(p); + } else if(c == 'x'){ + p->state->fn = state_hex; + p->state->ival = 0; + p->state->count = 0; + } else { + p->state->fn = state_octal; + p->state->ival = 0; + p->state->count = 0; + err = Parser_input_char(p, c); + } + exit: + return err; +} + +int octaldone(Parser *p){ + int err = 0; + char d = (char)(p->state->ival & 0xff); + err = Parser_pop(p); + if(err) goto exit; + err = Parser_input_char(p, d); + exit: + return err; +} + +int octaldigit(Parser *p, char c){ + int err = 0; + p->state->ival *= 8; + p->state->ival += c - '0'; + p->state->count++; + if(err) goto exit; + if(p->state->ival < 0 || p->state->ival > 0xff){ + parse_error(p); + err = -EINVAL; + goto exit; + } + if(p->state->count == 3){ + err = octaldone(p); + } + exit: + return err; +} + +int state_octal(Parser *p, char c){ + int err = 0; + if(at_eof(p)){ + parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF); + err = -EINVAL; + goto exit; + } else if('0' <= c && c <= '7'){ + err = octaldigit(p, c); + } else { + err = octaldone(p); + if(err) goto exit; + Parser_input_char(p, c); + } + exit: + return err; +} + +int hexdone(Parser *p){ + int err = 0; + char d = (char)(p->state->ival & 0xff); + err = Parser_pop(p); + if(err) goto exit; + err = Parser_input_char(p, d); + exit: + return err; +} + +int hexdigit(Parser *p, char c, char d){ + int err = 0; + p->state->ival *= 16; + p->state->ival += c - d; + p->state->count++; + if(err) goto exit; + if(p->state->ival < 0 || p->state->ival > 0xff){ + parse_error(p); + err = -EINVAL; + goto exit; + } + if(p->state->count == 2){ + err = hexdone(p); + } + exit: + return err; +} + +int state_hex(Parser *p, char c){ + int err = 0; + if(at_eof(p)){ + parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF); + err = -EINVAL; + goto exit; + } else if('0' <= c && c <= '9'){ + err = hexdigit(p, c, '0'); + } else if('A' <= c && c <= 'F'){ + err = hexdigit(p, c, 'A'); + } else if('a' <= c && c <= 'f'){ + err = hexdigit(p, c, 'a'); + } else if(p->state->count){ + err =hexdone(p); + if(err) goto exit; + Parser_input_char(p, c); + } + exit: + return err; +} + +int begin_atom(Parser *p, char c){ + int err = 0; + err = Parser_push(p, state_atom); + if(err) goto exit; + newtoken(p); + err = savechar(p, c); + exit: + return err; +} + +int state_atom(Parser *p, char c){ + int err = 0; + if(at_eof(p)){ + err = end_atom(p); + } else if(is_separator(p, c) || + in_space_class(c) || + in_comment_class(c)){ + err = end_atom(p); + if(err) goto exit; + err = Parser_input_char(p, c); + } else { + err = savechar(p, c); + } + exit: + return err; +} + +int end_atom(Parser *p){ + int err = 0; + err = do_intern(p); + if(err) goto exit; + err = Parser_return(p); + exit: + return err; +} + +int state_list(Parser *p, char c){ + int err = 0; + if(at_eof(p)){ + parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF); + err = -EINVAL; + } else if(c == c_list_close){ + p->state->val = nrev(p->state->val); + err = end_list(p); + } else { + err = state_start(p, c); + } + return err; + +} + +int begin_list(Parser *p, char c){ + return Parser_push(p, state_list); +} + +int end_list(Parser *p){ + return Parser_return(p); +} + +/** Reset the fields of a parser to initial values. + * + * @param z parser + */ +static void reset(Parser *z){ + IOStream *error_out = z->error_out; + int flags = z->flags; + zero(z, sizeof(Parser)); + z->buf_n = sizeof(z->buf) - 1; + z->buf_i = 0; + z->line_no = 1; + z->char_no = 0; + z->error_out = error_out; + z->flags = flags; +} + +/** Set the parser error stream. + * Parse errors are reported on the the error stream if it is non-null. + * + * @param z parser + * @param error_out error stream + */ +void set_error_stream(Parser *z, IOStream *error_out){ + if(z){ + z->error_out = error_out; + } +} + +/** Get the parser error message for an error code. + * + * @param id error code + * @return error message (empty string if the code is unknown) + */ +static char *get_message(ParseErrorId id){ + int i; + for(i=0; iline_no; +} + +/** Get the column number. + * + * @param in parser + */ +int get_column(Parser *in){ + return in->char_no; +} + +/** Get the line number the current token started on. + * + * @param in parser + */ +int get_tok_line(Parser *in){ + return in->tok_begin_line; +} + +/** Get the column number the current token started on. + * + * @param in parser + */ +int get_tok_column(Parser *in){ + return in->tok_begin_char; +} + +/** Report a parse error. + * Does nothing if the error stream is null or there is no error. + * + * @param in parser + */ +static void report_error(Parser *in){ + if(in->error_out && in->err){ + char *msg = get_message(in->err); + char *tok = peek_token(in); + IOStream_print(in->error_out, PARSE_ERR_FMT, + get_tok_line(in), get_tok_column(in), msg); + if(tok && tok[0]){ + IOStream_print(in->error_out, " '%s'", tok); + } + IOStream_print(in->error_out, "\n"); + } +} + +/** Get the error message for the current parse error code. + * Does nothing if there is no error. + * + * @param in parser + * @param buf where to place the message + * @param n maximum number of characters to place in buf + * @return current error code (zero for no error) + */ +int parse_error_message(Parser *in, char *buf, int n){ + if(in->err){ + char *msg = get_message(in->err); + snprintf(buf, n, PARSE_ERR_FMT, get_tok_line(in), get_tok_column(in), msg); + } + return in->err; +} + +/** Flag an unspecified parse error. All subsequent reads will fail. + * + * @param in parser + */ +void parse_error(Parser *in){ + parse_error_id(in, PARSE_ERR_INVALID_SYNTAX); +} + +/** Flag a parse error. All subsequent reads will fail. + * Does not change the parser error code if it is already set. + * + * @param in parser + * @param id error code + */ +void parse_error_id(Parser *in, ParseErrorId id){ + if(!in->err){ + in->err = id; + report_error(in); + } +} + +/** Test if the parser's error flag is set. + * + * @param in parser + * @return 1 if set, 0 otherwise + */ +int has_error(Parser *in){ + return (in->err > 0); +} + +/** Test if the parser is at end of input. + * + * @param in parser + * @return 1 if at EOF, 0 otherwise + */ +int at_eof(Parser *p){ + return p->eof; +} + +#ifdef SXPR_PARSER_MAIN +/* Stuff for standalone testing. */ + +#include "file_stream.h" +#include "string_stream.h" + +int stringof(Sxpr exp, char **s){ + int err = 0; + if(ATOMP(exp)){ + *s = atom_name(exp); + } else if(STRINGP(exp)){ + *s = string_string(exp); + } else { + err = -EINVAL; + *s = NULL; + } + return err; +} + +int child_string(Sxpr exp, Sxpr key, char **s){ + int err = 0; + Sxpr val = sxpr_child_value(exp, key, ONONE); + err = stringof(val, s); + return err; +} + +int intof(Sxpr exp, int *v){ + int err = 0; + char *s; + unsigned long l; + if(INTP(exp)){ + *v = OBJ_INT(exp); + } else { + err = stringof(exp, &s); + if(err) goto exit; + err = convert_atoul(s, &l); + *v = (int)l; + } + exit: + return err; +} + +int child_int(Sxpr exp, Sxpr key, int *v){ + int err = 0; + Sxpr val = sxpr_child_value(exp, key, ONONE); + err = intof(val, v); + return err; +} + +int eval_vnet(Sxpr exp){ + int err = 0; + Sxpr oid = intern("id"); + int id; + err = child_int(exp, oid, &id); + if(err) goto exit; + dprintf("> vnet id=%d\n", id); + exit: + dprintf("< err=%d\n", err); + return err; +} + +int eval_connect(Sxpr exp){ + int err = 0; + Sxpr ovif = intern("vif"); + Sxpr ovnet = intern("vnet"); + char *vif; + int vnet; + + err = child_string(exp, ovif, &vif); + if(err) goto exit; + err = child_int(exp, ovnet, &vnet); + if(err) goto exit; + dprintf("> connect vif=%s vnet=%d\n", vif, vnet); + exit: + dprintf("< err=%d\n", err); + return err; +} + +int eval(Sxpr exp){ + int err = 0; + Sxpr oconnect = intern("connect"); + Sxpr ovnet = intern("vnet"); + + if(sxpr_elementp(exp, ovnet)){ + err = eval_vnet(exp); + } else if(sxpr_elementp(exp, oconnect)){ + err = eval_connect(exp); + } else { + err = -EINVAL; + } + return err; +} + +/** Main program for testing. + * Parses input and prints it. + * + * @param argc number of arguments + * @param argv arguments + * @return error code + */ +int main(int argc, char *argv[]){ + Parser *pin; + int err = 0; + char buf[1024]; + int k; + Sxpr obj, l, x; + + pin = Parser_new(); + set_error_stream(pin, iostdout); + dprintf("> parse...\n"); + while(1){ + k = fread(buf, 1, 1024, stdin); + err = Parser_input(pin, buf, k); + dprintf("> Parser_input=%d\n", err); + if(k <= 0) break; + } + obj = pin->val; + for(l = obj ; CONSP(l); l = CDR(l)){ + x = CAR(l); + objprint(iostdout, x, 0); printf("\n"); + eval(x); + } + dprintf("> err=%d\n", err); + return 0; +} +#endif diff --git a/tools/libxutil/sxpr_parser.h b/tools/libxutil/sxpr_parser.h new file mode 100644 index 0000000000..7296312e44 --- /dev/null +++ b/tools/libxutil/sxpr_parser.h @@ -0,0 +1,125 @@ +/* + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of the + * License, or (at your option) any later version. This library is + * distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _XEN_LIB_SXPR_PARSER_H_ +#define _XEN_LIB_SXPR_PARSER_H_ + +#include "sxpr.h" +#include "iostream.h" + +/** @file + * Sxpr parsing definitions. + */ + +/** Size of a parser input buffer. + * Tokens read must fit into this size (including trailing null). + */ +#define PARSER_BUF_SIZE 1024 + +struct Parser; +typedef int ParserStateFn(struct Parser *, char c); + +typedef struct ParserState { + struct ParserState *parent; + Sxpr val; + int ival; + int count; + char delim; + ParserStateFn *fn; +} ParserState; + +/** Structure representing an input source for the parser. + * Can read from any IOStream implementation. + */ +typedef struct Parser { + Sxpr val; + /** Error reporting stream (null for no reports). */ + IOStream *error_out; + int eof; + /** Error flag. Non-zero if there has been a read error. */ + int err; + /** Line number on input (from 1). */ + int line_no; + /** Column number of input (reset on new line). */ + int char_no; + /** Lookahead character. */ + char c; + /** Buffer for reading tokens. */ + char buf[PARSER_BUF_SIZE]; + /** Size of token buffer. */ + int buf_n; + int buf_i; + /** Line the last token started on. */ + int tok_begin_line; + /** Character number the last token started on. */ + int tok_begin_char; + /** Parsing flags. */ + int flags; + ParserState *state; +} Parser; + +/** Parser error codes. */ +typedef enum { + PARSE_ERR_NONE=0, + PARSE_ERR_UNSPECIFIED, + PARSE_ERR_NOMEM, + PARSE_ERR_UNEXPECTED_EOF, + PARSE_ERR_TOKEN_TOO_LONG, + PARSE_ERR_INVALID_SYNTAX, + PARSE_ERR_INVALID_ESCAPE, +} ParseErrorId; + + +/** Parser flags. */ +//enum { +//}; + +/** Raise some parser flags. + * + * @param in parser + * @param flags flags mask + */ +inline static void parser_flags_raise(Parser *in, int flags){ + in->flags |= flags; +} + +/** Lower some parser flags. + * + * @param in parser + * @param flags flags mask + */ +inline static void parser_flags_lower(Parser *in, int flags){ + in->flags &= ~flags; +} + +/** Clear all parser flags. + * + * @param in parser + */ +inline static void parser_flags_clear(Parser *in){ + in->flags = 0; +} + +extern void Parser_free(Parser *z); +extern Parser * Parser_new(void); +extern int Parser_input(Parser *p, char *buf, int buf_n); +extern int Parser_input_eof(Parser *p); + +extern int parse_error_message(Parser *in, char *buf, int n); +extern int has_error(Parser *in); +extern int at_eof(Parser *in); + +#endif /* ! _XEN_LIB_SXPR_PARSER_H_ */ diff --git a/tools/libxutil/sys_ctype.h b/tools/libxutil/sys_ctype.h new file mode 100644 index 0000000000..1dc6cf2fac --- /dev/null +++ b/tools/libxutil/sys_ctype.h @@ -0,0 +1,12 @@ +#ifndef _XENO_SYS_CTYPE_H_ +#define _XENO_SYS_CTYPE_H_ +/** @file + ** Replacement for ctype include that can be used + * from user or kernel code. + */ +#ifdef __KERNEL__ +# include +#else +# include +#endif +#endif /* ! _XENO_SYS_CTYPE_H_ */ diff --git a/tools/libxutil/sys_net.c b/tools/libxutil/sys_net.c new file mode 100644 index 0000000000..0e7ac5d638 --- /dev/null +++ b/tools/libxutil/sys_net.c @@ -0,0 +1,309 @@ +/* + * Copyright (C) 2001 - 2004 Mike Wray + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of the + * License, or (at your option) any later version. This library is + * distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "sys_net.h" +#include "sys_string.h" + +/** @file + * All network data are kept in network order and only converted to + * host order for display. Network data includes IP addresses, port numbers and + * network masks. + */ + +/** Maximum value for a port. */ +#define PORT_MAX 0xffff + +/** Convert a number of bits to a network mask + * for IP addresses. The number of bits must + * be in the range 1-31. + * + * @param n number of bits to set in the mask + * @return value with n high bits set (in network order) + */ +unsigned long bits_to_mask(int n){ + unsigned long mask = (n ? (1 << 31) : 0); + int i; + for(i=1; i> 1); + } + return htonl(mask); +} + +/** Convert a network mask to a number of bits. + * + * @param mask network mask in network order + * @return number of bits in mask + */ +int mask_to_bits(unsigned long mask){ + // Start with n set to the number of bits in the mask. Then reduce n by + // the number of low zero bits in the mask. + int n = 32; + for(mask = ntohl(mask); + (mask & 1)==0 && n>0; + mask >>= 1){ + n--; + } + return n; +} + +/** Get the index of the first occurrence of a character in a string. + * Stops at end of string or after n characters. + * + * @param s input string + * @param n maximum number of charactes to search + * @param c character to look for + * @return index of first occurrence, -1 if not found + */ +inline static int indexof(const char *s, int n, char c){ + int i; + for(i=0; i= sizeof(buf)){ + goto exit; + } + for(i=0; i < WORD_BYTES; i++){ + int idx = indexof(s, n, dot); + idx = (idx < 0 ? strlen(s) : idx); + strncpy(buf, s, idx); buf[idx]='\0'; + if(convert_atoul(buf, &v)){ + goto exit; + } + if(v < 0 || v > ADDR_MAX){ + goto exit; + } + addr |= (v << shift); + if(idx == n) break; + shift -= BYTE_BITS; + s += idx+1; + } + err = 0; + exit: + addr = htonl(addr); + *address = (err ? 0 : addr); + return err; +} + +#ifdef __KERNEL__ +/** Convert an address in network order to IPv4 dot notation. + * The return value is a static buffer which is overwritten on each call. + * + * @param inaddr address (in network order) + * @return address in dot notation + */ +char *inet_ntoa(struct in_addr inaddr){ + static char address[16] = {}; + uint32_t addr = ntohl(inaddr.s_addr); + snprintf(address, sizeof(address), "%d.%d.%d.%d", + (unsigned)((addr >> 24) & 0xff), + (unsigned)((addr >> 16) & 0xff), + (unsigned)((addr >> 8) & 0xff), + (unsigned)((addr ) & 0xff)); + return address; +} + + +/** Convert a string in IPv4 dot notation to an int in network order. + * + * @param address address in dot notation + * @param inp result of conversion (in network order) + * @return 0 on success, error code on error + */ +int inet_aton(const char *address, struct in_addr *inp){ + int err = 0; + unsigned long addr; + + err = get_inet_addr(address, &addr); + if(err) goto exit; + inp->s_addr = addr; + exit: + return err; +} +#endif + +/** Convert a hostname or IPv4 address string to an address in network order. + * + * @param name input hostname or address string + * @param address where to put the address + * @return 1 if address found OK, 0 otherwise + */ +int get_host_address(const char *name, unsigned long *address){ +#ifdef __KERNEL__ + return get_inet_addr(name, address) == 0; +#else + struct hostent *host = gethostbyname(name); + if(!host){ + return 0; + } + *address = ((struct in_addr *)(host->h_addr))->s_addr; + return 1; +#endif +} + +/** Convert a service name to a port (in network order). + * + * @param name service name + * @param port where to put the port + * @return 1 if service port found OK, 0 otherwise + */ +int get_service_port(const char *name, unsigned long *port){ +#ifdef __KERNEL__ + return 0; +#else + struct servent *service; + service = getservbyname(name, 0); + if(!service){ + return 0; + } + *port = service->s_port; + return 1; +#endif +} + +/** Convert a port number (in network order) to a service name. + * + * @param port the port number + * @return service name if found OK, 0 otherwise + */ +char *get_port_service(unsigned long port){ +#ifdef __KERNEL__ + return 0; +#else + struct servent *service = getservbyport(port, 0); + return (service ? service->s_name : 0); +#endif +} + +/** Convert a decimal integer or service name to a port (in network order). + * + * @param s input to convert + * @param port where to put the port + * @return 1 if port found OK, 0 otherwise + */ +int convert_service_to_port(const char *s, unsigned long *port){ + int ok = 0; + unsigned long value; + if(convert_atoul(s, &value)){ + ok = get_service_port(s, &value); + } else { + ok = (0 <= value) && (value <= PORT_MAX); + value = htons((unsigned short)value); + } + *port = (ok ? value : 0); + return ok; +} + +#define MAC_ELEMENT_N 6 // Number of elements in a MAC address. +#define MAC_DIGIT_N 2 // Number of digits in an element in a MAC address. +#define MAC_LENGTH 17 //((MAC_ELEMENT_N * MAC_DIGIT_N) + MAC_ELEMENT_N - 1) + +/** Convert a mac address from a string of the form + * XX:XX:XX:XX:XX:XX to numerical form (an array of 6 unsigned chars). + * Each X denotes a hex digit: 0..9, a..f, A..F. + * Also supports using '-' as the separator instead of ':'. + * + * @param mac_in string to convert + * @param mac destination for the value + * @return 0 on success, -1 on error + */ +int mac_aton(const char *mac_in, unsigned char *mac){ + int err = 0; + int i, j; + const char *p; + char sep = 0; + unsigned char d; + if(!mac_in || strlen(mac_in) != MAC_LENGTH){ + err = -1; + goto exit; + } + for(i = 0, p = mac_in; i < MAC_ELEMENT_N; i++){ + d = 0; + if(i){ + if(!sep){ + if(*p == ':' || *p == '-') sep = *p; + } + if(sep && *p == sep){ + p++; + } else { + err = -1; + goto exit; + } + } + for(j = 0; j < MAC_DIGIT_N; j++, p++){ + if(j) d <<= 4; + if(*p >= '0' && *p <= '9'){ + d += (*p - '0'); + } else if(*p >= 'A' && *p <= 'F'){ + d += (*p - 'A') + 10; + } else if(*p >= 'a' && *p <= 'f'){ + d += (*p - 'a') + 10; + } else { + err = -1; + goto exit; + } + } + mac[i] = d; + } + exit: + return err; +} + +/** Convert a MAC address from numerical form to a string. + * + * @param mac address to convert + * @return static string value + */ +char *mac_ntoa(const unsigned char *mac){ + static char buf[MAC_LENGTH + 1]; + int buf_n = sizeof(buf); + + memset(buf, buf_n, 0); + snprintf(buf, buf_n, "%02x:%02x:%02x:%02x:%02x:%02x", + mac[0], mac[1], mac[2], + mac[3], mac[4], mac[5]); + buf[buf_n - 1] = '\0'; + return buf; +} diff --git a/tools/libxutil/sys_net.h b/tools/libxutil/sys_net.h new file mode 100644 index 0000000000..da6c1e8fd5 --- /dev/null +++ b/tools/libxutil/sys_net.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2001 - 2004 Mike Wray + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _XEN_LIB_SYS_NET_H_ +#define _XEN_LIB_SYS_NET_H_ +/** @file + * + * Replacement for standard network includes. + * Works in user or kernel code. + */ + +extern int get_inet_addr(const char *s, unsigned long *address); +extern unsigned long bits_to_mask(int n); +extern int mask_to_bits(unsigned long mask); +extern int get_host_address(const char *name, unsigned long *address); +extern int get_service_port(const char *name, unsigned long *port); +extern char *get_port_service(unsigned long port); +extern int convert_service_to_port(const char *s, unsigned long *port); + +#ifdef __KERNEL__ +#include +#include +#include +#include +#include + +#ifndef htonl +#define htonl(x) __constant_htonl(x) +#endif + +#ifndef ntohl +#define ntohl(x) __constant_ntohl(x) +#endif + +#ifndef htons +#define htons(x) __constant_htons(x) +#endif + +#ifndef ntohs +#define ntohs(x) __constant_ntohs(x) +#endif + +#include +extern char *inet_ntoa(struct in_addr inaddr); +extern int inet_aton(const char *address, struct in_addr *inp); + +#else + +#include +#include +#include +#include +#include + +#endif + +extern char *mac_ntoa(const unsigned char *macaddr); +extern int mac_aton(const char *addr, unsigned char *macaddr); + +#endif /* !_SP_SYS_NET_H_ */ + + + diff --git a/tools/libxutil/sys_string.c b/tools/libxutil/sys_string.c new file mode 100644 index 0000000000..13a90dfd7d --- /dev/null +++ b/tools/libxutil/sys_string.c @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2001 - 2004 Mike Wray + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef __KERNEL__ +# include +# include +# include +# include +#else +# include +#endif + +#include "allocate.h" +#include "sys_string.h" + +/** Set the base to use for converting a string to a number. Base is + * hex if starts with 0x, otherwise decimal. + * + * @param s input string + * @param base where to put the base + * @return rest of s to parse as a number + */ +inline static const char * convert_set_base(const char *s, int *base){ + *base = 10; + if(s){ + if(*s=='0'){ + s++; + if(*s=='x' || *s=='X'){ + *base = 16; + s++; + } + } + } + return s; +} + +/** Get the numerical value of a digit in the given base. + * + * @param c digit character + * @param base to use + * @return numerical value of digit in range 0..base-1 or + * -1 if not in range for the base + */ +inline static int convert_get_digit(char c, int base){ + int d; + + if('0'<=c && c<='9'){ + d = c - '0'; + } else if('a'<=c && c<='f'){ + d = c - 'a' + 10; + } else if('A'<=c && c<='F'){ + d = c - 'A' + 10; + } else { + d = -1; + } + return (d < base ? d : -1); +} + +/** Convert a string to an unsigned long by parsing it as a number. + * Will accept hex or decimal in usual C syntax. + * + * @param str input string + * @param val where to put the result + * @return 0 if converted OK, negative otherwise + */ +int convert_atoul(const char *str, unsigned long *val){ + int err = 0; + unsigned long v = 0; + int base; + const char *s = str; + + if(!s) { + err = -EINVAL; + goto exit; + } + s = convert_set_base(s, &base); + for( ; !err && *s; s++){ + int digit = convert_get_digit(*s, base); + if(digit<0){ + err = -EINVAL; + goto exit; + } + v *= base; + v += digit; + } + exit: + *val = (err ? 0 : v); + return err; +} + +/** Combine a directory path with a relative path to produce + * a new path. + * + * @param s directory path + * @param t relative path + * @return new combined path s/t + */ +int path_concat(char *s, char *t, char **val){ + int err = 0; + int sn, tn, vn; + char *v; + sn = strlen(s); + if(sn > 0 && s[sn-1] == '/'){ + sn--; + } + tn = strlen(t); + if(tn > 0 && t[0] == '/'){ + tn--; + } + vn = sn+tn+1; + v = (char*)allocate(vn+1); + if(!v){ + err = -ENOMEM; + goto exit; + } + strncpy(v, s, sn); + v[sn] = '/'; + strncpy(v+sn+1, t, tn); + v[vn] = '\0'; + exit: + *val = (err ? NULL : v); + return err; +} diff --git a/tools/libxutil/sys_string.h b/tools/libxutil/sys_string.h new file mode 100644 index 0000000000..f39935f669 --- /dev/null +++ b/tools/libxutil/sys_string.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2001 - 2004 Mike Wray + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _XEN_LIB_SYS_STRING_H_ +#define _XEN_LIB_SYS_STRING_H_ +/** @file + * Replacement for standard string includes. + * Works in user or kernel code. + */ +/*============================================================================*/ +#ifdef __KERNEL__ + +#include +#include +#include +#include +#include +#include "allocate.h" + +#if 0 +static inline int tolower(int c){ + return (c>='A' && c<='Z' ? (c-'A')+'a' : c); +} +#endif + +static inline int isalpha(int c){ + return (c>='A' && c<='Z') || (c>='a' && c<='z'); +} + +static inline int isdigit(int c){ + return (c>='0' && c<='9'); +} + +#if 0 +static inline int strcasecmp(const char *s1, const char *s2){ + int c1, c2; + + do { + c1 = tolower(*s1++); + c2 = tolower(*s2++); + } while (c1 && c1 == c2); + return c1 - c2; +} +#endif + +static inline char * strdup(const char *s){ + int n = (s ? 1+strlen(s) : 0); + char *copy = (n ? allocate(n) : NULL); + if(copy){ + strcpy(copy, s); + } + return copy; +} + +/*============================================================================*/ +#else +#include +#include + +#ifndef _GNU_SOURCE +static inline size_t strnlen(const char *s, size_t n){ + int k = 0; + if(s){ + for(k=0; *s && k +/** @file + * XDR packer/unpacker for elements. + * + * string -> [T_STRING] [len:u32] + * atom -> [T_ATOM] [len:u32] + * uint -> [T_UINT] [value] + * cons -> [T_CONS] + * null -> [T_NULL] + * none -> [T_NONE] + * bool -> [T_BOOL] { 0:u8 | 1:u8 } + * + * types packed as u16. + * + * So (a b c) -> [T_CONS] a [T_CONS] b [T_CONS] c [T_NULL] + * () -> [T_NULL] + */ + +int pack_bool(IOStream *io, int x){ + int err=0; + err = IOStream_print(io, "%c", 0xff & x); + if(err > 0) err = 0; + return err; +} + +int unpack_bool(IOStream *io, int *x){ + int err = 0; + int c; + c = IOStream_getc(io); + *x = (c < 0 ? 0 : c); + err = IOStream_error(io); + if(c < 0 && !err) err = -EIO; + return err; +} + +int pack_ushort(IOStream *io, unsigned short x){ + int err=0; + err = IOStream_print(io, "%c%c", + 0xff & (x >> 8), + 0xff & (x )); + if(err > 0) err = 0; + return err; +} + +int unpack_ushort(IOStream *io, unsigned short *x){ + int err = 0; + int i, c = 0; + *x = 0; + for(i = 0; i< 2; i++){ + c = IOStream_getc(io); + if(c < 0) break; + *x <<= 8; + *x |= (0xff & c); + } + err = IOStream_error(io); + if(c < 0 && !err) err = -EIO; + return err; +} + +int pack_uint(IOStream *io, unsigned int x){ + int err=0; + err = IOStream_print(io, "%c%c%c%c", + 0xff & (x >> 24), + 0xff & (x >> 16), + 0xff & (x >> 8), + 0xff & (x )); + if(err > 0) err = 0; + return err; +} + +int unpack_uint(IOStream *io, unsigned int *x){ + int err = 0; + int i, c = 0; + *x = 0; + for(i = 0; i< 4; i++){ + c = IOStream_getc(io); + if(c < 0) break; + *x <<= 8; + *x |= (0xff & c); + } + err = IOStream_error(io); + if(c < 0 && !err) err = -EIO; + return err; +} + +int pack_string(IOStream *io, Sxpr x){ + int err = 0; + int n = string_length(x); + char *s = string_string(x); + int i; + err = pack_uint(io, n); + if(err) goto exit; + for(i = 0; i < n; i++){ + err = IOStream_print(io, "%c", s[i]); + if(err < 0) break; + } + if(err > 0) err = 0; + exit: + return err; +} + +int unpack_string(IOStream *io, Sxpr *x){ + int err; + unsigned int n; + int i, c = 0; + char *s; + Sxpr val = ONONE; + + err = unpack_uint(io, &n); + if(err) goto exit; + val = halloc(n+1, T_STRING); + if(NOMEMP(val)){ + err = -ENOMEM; + goto exit; + } + s = string_string(val); + for(i=0; iname); + break; + case T_STRING: + err = pack_string(io, x); + break; + case T_UINT: + err = pack_uint(io, get_ul(x)); + break; + default: + err = -EINVAL; + IOStream_print(iostderr, "%s> invalid type %d\n", __FUNCTION__, type); + break; + } + exit: + return err; +} + +int unpack_sxpr(IOStream *io, Sxpr *x){ + int err = 0; + unsigned short type; + unsigned int u; + Sxpr val = ONONE, y; + + err = unpack_ushort(io, &type); + if(err) goto exit; + switch(type){ + case T_NULL: + val = ONULL; + break; + case T_NONE: + val = ONONE; + break; + case T_CONS: + err = unpack_cons(io, &val); + break; + case T_BOOL: + err = unpack_bool(io, &u); + if(err) goto exit; + val = (u ? OTRUE : OFALSE); + break; + case T_ATOM: + err = unpack_string(io, &y); + if(err) goto exit; + val = intern(string_string(y)); + objfree(y); + break; + case T_STRING: + err = unpack_string(io, &val); + break; + case T_UINT: + err = unpack_uint(io, &u); + if(err) goto exit; + val = OBJI(type, u); + break; + default: + err = -EINVAL; + IOStream_print(iostderr, "%s> invalid type %d\n", __FUNCTION__, type); + break; + } + exit: + *x = (err ? ONONE : val); + return err; +} diff --git a/tools/libxutil/xdr.h b/tools/libxutil/xdr.h new file mode 100644 index 0000000000..cb7d97df95 --- /dev/null +++ b/tools/libxutil/xdr.h @@ -0,0 +1,14 @@ +/* $Id: xdr.h,v 1.2 2003/09/29 13:40:00 mjw Exp $ */ +#ifndef _SP_XDR_H_ +#define _SP_XDR_H_ +#include "iostream.h" +#include "sxpr.h" +int pack_uint(IOStream *out, unsigned int x); +int unpack_uint(IOStream *in, unsigned int *x); +int pack_string(IOStream *out, Sxpr x); +int unpack_string(IOStream *in, Sxpr *x); +int pack_cons(IOStream *out, Sxpr x); +int unpack_cons(IOStream *in, Sxpr *x); +int pack_sxpr(IOStream *out, Sxpr x); +int unpack_sxpr(IOStream *in, Sxpr *x); +#endif /* _SP_XDR_H_ */ diff --git a/tools/misc/Makefile b/tools/misc/Makefile index 9df04d8ea2..9795997364 100644 --- a/tools/misc/Makefile +++ b/tools/misc/Makefile @@ -1,10 +1,18 @@ +XEN_ROOT=../.. +include $(XEN_ROOT)/tools/Make.defs + CC = gcc CFLAGS = -Wall -O3 -EXTRA_INC = -I../../xen/include/hypervisor-ifs -EXTRA_INC += -I../../linux-xen-sparse/include -I../xc/lib -EXTRA_INC += -I../xu/lib -EXTRA_INC += -I../lib + +INCLUDES += -I $(XEN_HYPERVISOR_IFS) +INCLUDES += -I $(XEN_LINUX_INCLUDE) +INCLUDES += -I $(XEN_XC) +INCLUDES += -I $(XEN_XU) +INCLUDES += -I $(XEN_LIBXC) +INCLUDES += -I $(XEN_LIBXUTIL) + +CFLAGS += $(INCLUDES) HDRS = $(wildcard *.h) SRCS = $(wildcard *.c) @@ -12,7 +20,8 @@ OBJS = $(patsubst %.c,%.o,$(SRCS)) TARGETS = xen_cpuperf -INSTALL = $(TARGETS) xencons +INSTALL_BIN = $(TARGETS) xencons +INSTALL_SBIN = netfix xm xend all: $(TARGETS) $(MAKE) -C miniterm @@ -20,8 +29,8 @@ all: $(TARGETS) install: all mkdir -p $(prefix)/usr/bin mkdir -p $(prefix)/usr/sbin - install -m0755 $(INSTALL) $(prefix)/usr/bin - install -m0755 netfix $(prefix)/usr/sbin + install -m0755 $(INSTALL_BIN) $(prefix)/usr/bin + install -m0755 $(INSTALL_SBIN) $(prefix)/usr/sbin $(MAKE) -C miniterm install clean: @@ -29,4 +38,4 @@ clean: $(MAKE) -C miniterm clean %: %.c $(HDRS) Makefile - $(CC) $(CFLAGS) $(EXTRA_INC) -o $@ $< + $(CC) $(CFLAGS) -o $@ $< diff --git a/tools/misc/netfix b/tools/misc/netfix index def4e28a6c..df38e438a1 100644 --- a/tools/misc/netfix +++ b/tools/misc/netfix @@ -1,5 +1,6 @@ -#!/usr/bin/python +#!/usr/bin/env python # -*- mode: python; -*- +#============================================================================ # Copyright (C) 2004 Mike Wray #============================================================================ # Move the IP address from eth0 onto the Xen bridge (nbe-br). @@ -7,7 +8,7 @@ #============================================================================ from getopt import getopt -from xen.xend.XendBridge import * +from xen.util.Brctl import * short_options = 'hvqni:b:c' long_options = ['help', 'verbose', 'quiet', diff --git a/tools/misc/xend b/tools/misc/xend new file mode 100644 index 0000000000..06006490a4 --- /dev/null +++ b/tools/misc/xend @@ -0,0 +1,45 @@ +#!/usr/bin/env python +# -*- mode: python; -*- +#============================================================================ +# Copyright (C) 2004 Mike Wray +#============================================================================ + +"""Xen management daemon. Lives in /usr/sbin. + Provides console server and HTTP management api. + + Run: + + xend start + + The daemon is stopped with: + + xend stop + + The daemon should reconnect to device control interfaces + and recover its state when restarted. +""" +import os +import sys +from xen.xend.server import SrvDaemon + +def main(): + daemon = SrvDaemon.instance() + if not sys.argv[1:]: + print 'usage: %s {start|stop|restart}' % sys.argv[0] + elif os.fork(): + pid, status = os.wait() + return status >> 8 + elif sys.argv[1] == 'start': + return daemon.start() + elif sys.argv[1] == 'trace_start': + return daemon.start(trace=1) + elif sys.argv[1] == 'stop': + return daemon.stop() + elif sys.argv[1] == 'restart': + return daemon.stop() or daemon.start() + else: + print 'not an option:', sys.argv[1] + return 1 + +if __name__ == '__main__': + sys.exit(main()) diff --git a/tools/misc/xm b/tools/misc/xm new file mode 100755 index 0000000000..6ace888cda --- /dev/null +++ b/tools/misc/xm @@ -0,0 +1,6 @@ +#!/usr/bin/env python +# -*- mode: python; -*- +import sys +from xen.xm import main + +main.main(sys.argv) diff --git a/tools/python/Makefile b/tools/python/Makefile new file mode 100644 index 0000000000..7dc74a1072 --- /dev/null +++ b/tools/python/Makefile @@ -0,0 +1,15 @@ + +all: + python setup.py build + +install: all + if [ "$(prefix)" = "" ]; then \ + python setup.py install; \ + elif [ "$(dist)" = "yes" ]; then \ + python setup.py install --home="$(prefix)"; \ + else \ + python setup.py install --root="$(prefix)"; \ + fi + +clean: + rm -rf build *.pyc *.pyo *.o *.a *~ diff --git a/tools/python/setup.py b/tools/python/setup.py new file mode 100644 index 0000000000..b0eb3f2ebd --- /dev/null +++ b/tools/python/setup.py @@ -0,0 +1,48 @@ + +from distutils.core import setup, Extension + +XEN_ROOT = "../.." + +extra_compile_args = ["-fno-strict-aliasing"] + + +include_dirs = [ XEN_ROOT + "/xen/include/hypervisor-ifs", + XEN_ROOT + "/linux-xen-sparse/include", + XEN_ROOT + "/tools/python/xen/ext/xu", + XEN_ROOT + "/tools/libxc", + XEN_ROOT + "/tools/libxutil", + ] + +library_dirs = [ XEN_ROOT + "/tools/libxc", + XEN_ROOT + "/tools/libxutil", + ] + +libraries = [ "xc", "xutil" ] + +xc = Extension("xc", + extra_compile_args = extra_compile_args, + include_dirs = include_dirs + [ "xen/ext/xc" ], + library_dirs = library_dirs, + libraries = libraries, + sources = [ "xen/ext/xc/xc.c" ]) + +xu = Extension("xu", + extra_compile_args = extra_compile_args, + include_dirs = include_dirs + [ "xen/ext/xu" ], + library_dirs = library_dirs, + libraries = libraries, + sources = [ "xen/ext/xu/xu.c" ]) + +setup(name = 'xen', + version = '2.0', + description = 'Xen', + packages = ['xen', + 'xen.ext', + 'xen.util', + 'xen.xend', + 'xen.xend.server', + 'xen.xm', + ], + ext_package = "xen.ext", + ext_modules = [ xc, xu ] + ) diff --git a/tools/python/xen/__init__.py b/tools/python/xen/__init__.py new file mode 100644 index 0000000000..8d1c8b69c3 --- /dev/null +++ b/tools/python/xen/__init__.py @@ -0,0 +1 @@ + diff --git a/tools/python/xen/ext/__init__.py b/tools/python/xen/ext/__init__.py new file mode 100644 index 0000000000..8d1c8b69c3 --- /dev/null +++ b/tools/python/xen/ext/__init__.py @@ -0,0 +1 @@ + diff --git a/tools/python/xen/ext/xc/Makefile b/tools/python/xen/ext/xc/Makefile new file mode 100644 index 0000000000..7dc74a1072 --- /dev/null +++ b/tools/python/xen/ext/xc/Makefile @@ -0,0 +1,15 @@ + +all: + python setup.py build + +install: all + if [ "$(prefix)" = "" ]; then \ + python setup.py install; \ + elif [ "$(dist)" = "yes" ]; then \ + python setup.py install --home="$(prefix)"; \ + else \ + python setup.py install --root="$(prefix)"; \ + fi + +clean: + rm -rf build *.pyc *.pyo *.o *.a *~ diff --git a/tools/python/xen/ext/xc/setup.py b/tools/python/xen/ext/xc/setup.py new file mode 100644 index 0000000000..8efe5ca1a0 --- /dev/null +++ b/tools/python/xen/ext/xc/setup.py @@ -0,0 +1,19 @@ + +from distutils.core import setup, Extension + +module = Extension("xc", + extra_compile_args = ["-fno-strict-aliasing"], + include_dirs = ["../lib", + "../../../xen/include/hypervisor-ifs", + "../../../linux-xen-sparse/include", + "../../xu/lib", + "../../lib" ], + library_dirs = ["../lib", + "../../lib" ], + libraries = ["xc"], + sources = ["Xc.c"]) + +setup(name = "xc", + version = "2.0", + ext_package = "xen.ext", + ext_modules = [module]) diff --git a/tools/python/xen/ext/xc/xc.c b/tools/python/xen/ext/xc/xc.c new file mode 100644 index 0000000000..2eb70cf2a0 --- /dev/null +++ b/tools/python/xen/ext/xc/xc.c @@ -0,0 +1,1160 @@ +/****************************************************************************** + * Xc.c + * + * Copyright (c) 2003-2004, K A Fraser (University of Cambridge) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xc_private.h" +#include "gzip_stream.h" + +/* Needed for Python versions earlier than 2.3. */ +#ifndef PyMODINIT_FUNC +#define PyMODINIT_FUNC DL_EXPORT(void) +#endif + +#define XENPKG "xen.ext.xc" + +static PyObject *xc_error, *zero; + +typedef struct { + PyObject_HEAD; + int xc_handle; +} XcObject; + +/* + * Definitions for the 'xc' object type. + */ + +static PyObject *pyxc_domain_create(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + unsigned int mem_kb = 0; + char *name = "(anon)"; + int cpu = -1; + u32 dom; + int ret; + + static char *kwd_list[] = { "mem_kb", "name", "cpu", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|isi", kwd_list, + &mem_kb, &name, &cpu) ) + return NULL; + + if ( (ret = xc_domain_create(xc->xc_handle, mem_kb, name, cpu, &dom)) < 0 ) + return PyErr_SetFromErrno(xc_error); + + return PyInt_FromLong(dom); +} + +static PyObject *pyxc_domain_pause(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + u32 dom; + + static char *kwd_list[] = { "dom", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &dom) ) + return NULL; + + if ( xc_domain_pause(xc->xc_handle, dom) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_domain_unpause(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + u32 dom; + + static char *kwd_list[] = { "dom", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &dom) ) + return NULL; + + if ( xc_domain_unpause(xc->xc_handle, dom) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_domain_destroy(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + u32 dom; + + static char *kwd_list[] = { "dom", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &dom) ) + return NULL; + + if ( xc_domain_destroy(xc->xc_handle, dom) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_domain_pincpu(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + u32 dom; + int cpu = -1; + + static char *kwd_list[] = { "dom", "cpu", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list, + &dom, &cpu) ) + return NULL; + + if ( xc_domain_pincpu(xc->xc_handle, dom, cpu) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_domain_getinfo(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + PyObject *list; + + u32 first_dom = 0; + int max_doms = 1024, nr_doms, i; + xc_dominfo_t *info; + + static char *kwd_list[] = { "first_dom", "max_doms", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwd_list, + &first_dom, &max_doms) ) + return NULL; + + if ( (info = malloc(max_doms * sizeof(xc_dominfo_t))) == NULL ) + return PyErr_NoMemory(); + + nr_doms = xc_domain_getinfo(xc->xc_handle, first_dom, max_doms, info); + + list = PyList_New(nr_doms); + for ( i = 0 ; i < nr_doms; i++ ) + { + PyList_SetItem( + list, i, + Py_BuildValue("{s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i" + ",s:l,s:L,s:s,s:l,s:i}", + "dom", info[i].domid, + "cpu", info[i].cpu, + "dying", info[i].dying, + "crashed", info[i].crashed, + "shutdown", info[i].shutdown, + "paused", info[i].paused, + "blocked", info[i].blocked, + "running", info[i].running, + "mem_kb", info[i].nr_pages*4, + "cpu_time", info[i].cpu_time, + "name", info[i].name, + "maxmem_kb", info[i].max_memkb, + "shutdown_reason", info[i].shutdown_reason + )); + } + + free(info); + + return list; +} + +static int file_save(XcObject *xc, XcIOContext *ctxt, char *state_file){ + int rc = -1; + int fd = -1; + int open_flags = (O_CREAT | O_EXCL | O_WRONLY); + int open_mode = 0644; + + printf("%s>\n", __FUNCTION__); + fd = open(state_file, open_flags, open_mode); + if(fd < 0){ + xcio_perror(ctxt, "Could not open file for writing"); + goto exit; + } + /* Compression rate 1: we want speed over compression. + * We're mainly going for those zero pages, after all. + */ + printf("%s>gzip_stream_fdopen... \n", __FUNCTION__); + ctxt->io = gzip_stream_fdopen(fd, "wb1"); + if(!ctxt->io){ + xcio_perror(ctxt, "Could not allocate compression state"); + goto exit; + } + printf("%s> xc_linux_save...\n", __FUNCTION__); + rc = xc_linux_save(xc->xc_handle, ctxt); + exit: + if(ctxt->io) IOStream_close(ctxt->io); + if(fd >= 0) close(fd); + unlink(state_file); + printf("%s> rc=%d\n", __FUNCTION__, rc); + return rc; +} + +static PyObject *pyxc_linux_save(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + u32 dom; + char *state_file; + int progress = 1, debug = 0; + unsigned int flags = 0; + PyObject *val = NULL; + int rc = -1; + XcIOContext ioctxt = { .info = iostdout, .err = iostderr }; + + static char *kwd_list[] = { "dom", "state_file", "vmconfig", "progress", "debug", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "is|sii", kwd_list, + &ioctxt.domain, + &state_file, + &ioctxt.vmconfig, + &progress, + &debug)){ + goto exit; + } + ioctxt.vmconfig_n = (ioctxt.vmconfig ? strlen(ioctxt.vmconfig) : 0); + if (progress) ioctxt.flags |= XCFLAGS_VERBOSE; + if (debug) ioctxt.flags |= XCFLAGS_DEBUG; + if(!state_file || state_file[0] == '\0') goto exit; + rc = file_save(xc, &ioctxt, state_file); + if(rc){ + PyErr_SetFromErrno(xc_error); + goto exit; + } + //xc_domain_destroy(xc->xc_handle, dom); + Py_INCREF(zero); + val = zero; + exit: + return val; +} + + +static int file_restore(XcObject *xc, XcIOContext *ioctxt, char *state_file){ + int rc = -1; + + ioctxt->io = gzip_stream_fopen(state_file, "rb"); + if (!ioctxt->io) { + xcio_perror(ioctxt, "Could not open file for reading"); + goto exit; + } + + rc = xc_linux_restore(xc->xc_handle, ioctxt); + exit: + if(ioctxt->io) IOStream_close(ioctxt->io); + return rc; +} + +static PyObject *pyxc_linux_restore(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + char *state_file; + int progress = 1, debug = 0; + u32 dom; + PyObject *val = NULL; + XcIOContext ioctxt = { .info = iostdout, .err = iostderr }; + int rc =-1; + + static char *kwd_list[] = { "state_file", "progress", "debug", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "is|ii", kwd_list, + &ioctxt.domain, + &state_file, + &progress, + &debug)){ + goto exit; + } + if (progress) ioctxt.flags |= XCFLAGS_VERBOSE; + if (debug) ioctxt.flags |= XCFLAGS_DEBUG; + + if(!state_file || state_file[0] == '\0') goto exit; + rc = file_restore(xc, &ioctxt, state_file); + if(rc){ + PyErr_SetFromErrno(xc_error); + goto exit; + } + val = Py_BuildValue("{s:i,s:s}", + "dom", ioctxt.domain, + "vmconfig", ioctxt.vmconfig); + //? free(ioctxt.vmconfig); + exit: + return val; +} + +static PyObject *pyxc_linux_build(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + u32 dom; + char *image, *ramdisk = NULL, *cmdline = ""; + int control_evtchn, flags = 0; + + static char *kwd_list[] = { "dom", "control_evtchn", + "image", "ramdisk", "cmdline", "flags", + NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iis|ssi", kwd_list, + &dom, &control_evtchn, + &image, &ramdisk, &cmdline, &flags) ) + return NULL; + + if ( xc_linux_build(xc->xc_handle, dom, image, + ramdisk, cmdline, control_evtchn, flags) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_netbsd_build(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + u32 dom; + char *image, *ramdisk = NULL, *cmdline = ""; + int control_evtchn; + + static char *kwd_list[] = { "dom", "control_evtchn", + "image", "ramdisk", "cmdline", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iis|ssi", kwd_list, + &dom, &control_evtchn, + &image, &ramdisk, &cmdline) ) + return NULL; + + if ( xc_netbsd_build(xc->xc_handle, dom, image, + cmdline, control_evtchn) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_bvtsched_global_set(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + unsigned long ctx_allow; + + static char *kwd_list[] = { "ctx_allow", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "l", kwd_list, &ctx_allow) ) + return NULL; + + if ( xc_bvtsched_global_set(xc->xc_handle, ctx_allow) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_bvtsched_global_get(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + unsigned long ctx_allow; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + if ( xc_bvtsched_global_get(xc->xc_handle, &ctx_allow) != 0 ) + return PyErr_SetFromErrno(xc_error); + + return Py_BuildValue("s:l", "ctx_allow", ctx_allow); +} + +static PyObject *pyxc_bvtsched_domain_set(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + u32 dom; + unsigned long mcuadv, warp, warpl, warpu; + + static char *kwd_list[] = { "dom", "mcuadv", "warp", "warpl", + "warpu", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "illll", kwd_list, + &dom, &mcuadv, &warp, &warpl, &warpu) ) + return NULL; + + if ( xc_bvtsched_domain_set(xc->xc_handle, dom, mcuadv, + warp, warpl, warpu) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_bvtsched_domain_get(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + u32 dom; + unsigned long mcuadv, warp, warpl, warpu; + + static char *kwd_list[] = { "dom", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &dom) ) + return NULL; + + if ( xc_bvtsched_domain_get(xc->xc_handle, dom, &mcuadv, &warp, + &warpl, &warpu) != 0 ) + return PyErr_SetFromErrno(xc_error); + + return Py_BuildValue("{s:i,s:l,s:l,s:l,s:l}", + "domain", dom, + "mcuadv", mcuadv, + "warp", warp, + "warpl", warpl, + "warpu", warpu); +} + +static PyObject *pyxc_evtchn_bind_interdomain(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + u32 dom1 = DOMID_SELF, dom2 = DOMID_SELF; + int port1, port2; + + static char *kwd_list[] = { "dom1", "dom2", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwd_list, + &dom1, &dom2) ) + return NULL; + + if ( xc_evtchn_bind_interdomain(xc->xc_handle, dom1, + dom2, &port1, &port2) != 0 ) + return PyErr_SetFromErrno(xc_error); + + return Py_BuildValue("{s:i,s:i}", + "port1", port1, + "port2", port2); +} + +static PyObject *pyxc_evtchn_bind_virq(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + int virq, port; + + static char *kwd_list[] = { "virq", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &virq) ) + return NULL; + + if ( xc_evtchn_bind_virq(xc->xc_handle, virq, &port) != 0 ) + return PyErr_SetFromErrno(xc_error); + + return PyInt_FromLong(port); +} + +static PyObject *pyxc_evtchn_close(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + u32 dom = DOMID_SELF; + int port; + + static char *kwd_list[] = { "port", "dom", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list, + &port, &dom) ) + return NULL; + + if ( xc_evtchn_close(xc->xc_handle, dom, port) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_evtchn_send(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + int port; + + static char *kwd_list[] = { "port", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &port) ) + return NULL; + + if ( xc_evtchn_send(xc->xc_handle, port) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_evtchn_status(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + PyObject *dict; + + u32 dom = DOMID_SELF; + int port, ret; + xc_evtchn_status_t status; + + static char *kwd_list[] = { "port", "dom", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list, + &port, &dom) ) + return NULL; + + ret = xc_evtchn_status(xc->xc_handle, dom, port, &status); + if ( ret != 0 ) + return PyErr_SetFromErrno(xc_error); + + switch ( status.status ) + { + case EVTCHNSTAT_closed: + dict = Py_BuildValue("{s:s}", + "status", "closed"); + break; + case EVTCHNSTAT_unbound: + dict = Py_BuildValue("{s:s}", + "status", "unbound"); + break; + case EVTCHNSTAT_interdomain: + dict = Py_BuildValue("{s:s,s:i,s:i}", + "status", "interdomain", + "dom", status.u.interdomain.dom, + "port", status.u.interdomain.port); + break; + case EVTCHNSTAT_pirq: + dict = Py_BuildValue("{s:s,s:i}", + "status", "pirq", + "irq", status.u.pirq); + break; + case EVTCHNSTAT_virq: + dict = Py_BuildValue("{s:s,s:i}", + "status", "virq", + "irq", status.u.virq); + break; + default: + dict = Py_BuildValue("{}"); + break; + } + + return dict; +} + +static PyObject *pyxc_physdev_pci_access_modify(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + u32 dom; + int bus, dev, func, enable, ret; + + static char *kwd_list[] = { "dom", "bus", "dev", "func", "enable", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiiii", kwd_list, + &dom, &bus, &dev, &func, &enable) ) + return NULL; + + ret = xc_physdev_pci_access_modify( + xc->xc_handle, dom, bus, dev, func, enable); + if ( ret != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_readconsolering(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + unsigned int clear = 0; + char str[32768]; + int ret; + + static char *kwd_list[] = { "clear", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwd_list, &clear) ) + return NULL; + + ret = xc_readconsolering(xc->xc_handle, str, sizeof(str), clear); + if ( ret < 0 ) + return PyErr_SetFromErrno(xc_error); + + return PyString_FromStringAndSize(str, ret); +} + +static PyObject *pyxc_physinfo(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + xc_physinfo_t info; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + if ( xc_physinfo(xc->xc_handle, &info) != 0 ) + return PyErr_SetFromErrno(xc_error); + + return Py_BuildValue("{s:i,s:i,s:l,s:l,s:l}", + "ht_per_core", info.ht_per_core, + "cores", info.cores, + "total_pages", info.total_pages, + "free_pages", info.free_pages, + "cpu_khz", info.cpu_khz); +} + +static PyObject *pyxc_atropos_domain_set(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + u32 domid; + u64 period, slice, latency; + int xtratime; + + static char *kwd_list[] = { "dom", "period", "slice", "latency", + "xtratime", NULL }; + + if( !PyArg_ParseTupleAndKeywords(args, kwds, "iLLLi", kwd_list, &domid, + &period, &slice, &latency, &xtratime) ) + return NULL; + + if ( xc_atropos_domain_set(xc->xc_handle, domid, period, slice, + latency, xtratime) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_atropos_domain_get(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + u32 domid; + u64 period, slice, latency; + int xtratime; + + static char *kwd_list[] = { "dom", NULL }; + + if( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &domid) ) + return NULL; + + if ( xc_atropos_domain_get( xc->xc_handle, domid, &period, + &slice, &latency, &xtratime ) ) + return PyErr_SetFromErrno(xc_error); + + return Py_BuildValue("{s:i,s:L,s:L,s:L,s:i}", + "domain", domid, + "period", period, + "slice", slice, + "latency", latency, + "xtratime", xtratime); +} + + +static PyObject *pyxc_rrobin_global_set(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + u64 slice; + + static char *kwd_list[] = { "slice", NULL }; + + if( !PyArg_ParseTupleAndKeywords(args, kwds, "L", kwd_list, &slice) ) + return NULL; + + if ( xc_rrobin_global_set(xc->xc_handle, slice) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_shadow_control(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + u32 dom; + int op=0; + + static char *kwd_list[] = { "dom", "op", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list, + &dom, &op) ) + return NULL; + + if ( xc_shadow_control(xc->xc_handle, dom, op, NULL, 0, NULL) < 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_rrobin_global_get(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + u64 slice; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + if ( xc_rrobin_global_get(xc->xc_handle, &slice) != 0 ) + return PyErr_SetFromErrno(xc_error); + + return Py_BuildValue("{s:L}", "slice", slice); +} + +static PyObject *pyxc_domain_setname(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + u32 dom; + char *name; + + static char *kwd_list[] = { "dom", "name", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "is", kwd_list, + &dom, &name) ) + return NULL; + + if ( xc_domain_setname(xc->xc_handle, dom, name) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_domain_setmaxmem(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + u32 dom; + unsigned long max_memkb; + + static char *kwd_list[] = { "dom", "max_memkb", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "ii", kwd_list, + &dom, &max_memkb) ) + return NULL; + + if ( xc_domain_setmaxmem(xc->xc_handle, dom, max_memkb) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + + +static PyMethodDef pyxc_methods[] = { + { "domain_create", + (PyCFunction)pyxc_domain_create, + METH_VARARGS | METH_KEYWORDS, "\n" + "Create a new domain.\n" + " mem_kb [int, 0]: Memory allocation, in kilobytes.\n" + " name [str, '(anon)']: Informative textual name.\n\n" + "Returns: [int] new domain identifier; -1 on error.\n" }, + + { "domain_pause", + (PyCFunction)pyxc_domain_pause, + METH_VARARGS | METH_KEYWORDS, "\n" + "Temporarily pause execution of a domain.\n" + " dom [int]: Identifier of domain to be paused.\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "domain_unpause", + (PyCFunction)pyxc_domain_unpause, + METH_VARARGS | METH_KEYWORDS, "\n" + "(Re)start execution of a domain.\n" + " dom [int]: Identifier of domain to be unpaused.\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "domain_destroy", + (PyCFunction)pyxc_domain_destroy, + METH_VARARGS | METH_KEYWORDS, "\n" + "Destroy a domain.\n" + " dom [int]: Identifier of domain to be destroyed.\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "domain_pincpu", + (PyCFunction)pyxc_domain_pincpu, + METH_VARARGS | METH_KEYWORDS, "\n" + "Pin a domain to a specified CPU.\n" + " dom [int]: Identifier of domain to be pinned.\n" + " cpu [int, -1]: CPU to pin to, or -1 to unpin\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "domain_getinfo", + (PyCFunction)pyxc_domain_getinfo, + METH_VARARGS | METH_KEYWORDS, "\n" + "Get information regarding a set of domains, in increasing id order.\n" + " first_dom [int, 0]: First domain to retrieve info about.\n" + " max_doms [int, 1024]: Maximum number of domains to retrieve info" + " about.\n\n" + "Returns: [list of dicts] if list length is less than 'max_doms'\n" + " parameter then there was an error, or the end of the\n" + " domain-id space was reached.\n" + " dom [int]: Identifier of domain to which this info pertains\n" + " cpu [int]: CPU to which this domain is bound\n" + " dying [int]: Bool - is the domain dying?\n" + " crashed [int]: Bool - has the domain crashed?\n" + " shutdown [int]: Bool - has the domain shut itself down?\n" + " paused [int]: Bool - is the domain paused by control software?\n" + " blocked [int]: Bool - is the domain blocked waiting for an event?\n" + " running [int]: Bool - is the domain currently running?\n" + " mem_kb [int]: Memory reservation, in kilobytes\n" + " cpu_time [long]: CPU time consumed, in nanoseconds\n" + " name [str]: Identifying name\n" + " shutdown_reason [int]: Numeric code from guest OS, explaining " + "reason why it shut itself down.\n" }, + + { "linux_save", + (PyCFunction)pyxc_linux_save, + METH_VARARGS | METH_KEYWORDS, "\n" + "Save the CPU and memory state of a Linux guest OS.\n" + " dom [int]: Identifier of domain to be saved.\n" + " state_file [str]: Name of state file. Must not currently exist.\n" + " progress [int, 1]: Bool - display a running progress indication?\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "linux_restore", + (PyCFunction)pyxc_linux_restore, + METH_VARARGS | METH_KEYWORDS, "\n" + "Restore the CPU and memory state of a Linux guest OS.\n" + " state_file [str]: Name of state file. Must not currently exist.\n" + " progress [int, 1]: Bool - display a running progress indication?\n\n" + "Returns: [int] new domain identifier on success; -1 on error.\n" }, + + { "linux_build", + (PyCFunction)pyxc_linux_build, + METH_VARARGS | METH_KEYWORDS, "\n" + "Build a new Linux guest OS.\n" + " dom [int]: Identifier of domain to build into.\n" + " image [str]: Name of kernel image file. May be gzipped.\n" + " ramdisk [str, n/a]: Name of ramdisk file, if any.\n" + " cmdline [str, n/a]: Kernel parameters, if any.\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "netbsd_build", + (PyCFunction)pyxc_netbsd_build, + METH_VARARGS | METH_KEYWORDS, "\n" + "Build a new NetBSD guest OS.\n" + " dom [int]: Identifier of domain to build into.\n" + " image [str]: Name of kernel image file. May be gzipped.\n" + " cmdline [str, n/a]: Kernel parameters, if any.\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "bvtsched_global_set", + (PyCFunction)pyxc_bvtsched_global_set, + METH_VARARGS | METH_KEYWORDS, "\n" + "Set global tuning parameters for Borrowed Virtual Time scheduler.\n" + " ctx_allow [int]: Minimal guaranteed quantum.\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "bvtsched_global_get", + (PyCFunction)pyxc_bvtsched_global_get, + METH_KEYWORDS, "\n" + "Get global tuning parameters for BVT scheduler.\n" + "Returns: [dict]:\n" + " ctx_allow [int]: context switch allowance\n" }, + + { "bvtsched_domain_set", + (PyCFunction)pyxc_bvtsched_domain_set, + METH_VARARGS | METH_KEYWORDS, "\n" + "Set per-domain tuning parameters for Borrowed Virtual Time scheduler.\n" + " dom [int]: Identifier of domain to be tuned.\n" + " mcuadv [int]: Proportional to the inverse of the domain's weight.\n" + " warp [int]: How far to warp domain's EVT on unblock.\n" + " warpl [int]: How long the domain can run warped.\n" + " warpu [int]: How long before the domain can warp again.\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "bvtsched_domain_get", + (PyCFunction)pyxc_bvtsched_domain_get, + METH_KEYWORDS, "\n" + "Get per-domain tuning parameters under the BVT scheduler.\n" + " dom [int]: Identifier of domain to be queried.\n" + "Returns [dict]:\n" + " domain [int]: Domain ID.\n" + " mcuadv [long]: MCU Advance.\n" + " warp [long]: Warp.\n" + " warpu [long]: Unwarp requirement.\n" + " warpl [long]: Warp limit,\n" + }, + + { "atropos_domain_set", + (PyCFunction)pyxc_atropos_domain_set, + METH_KEYWORDS, "\n" + "Set the scheduling parameters for a domain when running with Atropos.\n" + " dom [int]: domain to set\n" + " period [long]: domain's scheduling period\n" + " slice [long]: domain's slice per period\n" + " latency [long]: wakeup latency hint\n" + " xtratime [int]: boolean\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "atropos_domain_get", + (PyCFunction)pyxc_atropos_domain_get, + METH_KEYWORDS, "\n" + "Get the current scheduling parameters for a domain when running with\n" + "the Atropos scheduler." + " dom [int]: domain to query\n" + "Returns: [dict]\n" + " domain [int]: domain ID\n" + " period [long]: scheduler period\n" + " slice [long]: CPU reservation per period\n" + " latency [long]: unblocking latency hint\n" + " xtratime [int] : 0 if not using slack time, nonzero otherwise\n" }, + + { "rrobin_global_set", + (PyCFunction)pyxc_rrobin_global_set, + METH_KEYWORDS, "\n" + "Set Round Robin scheduler slice.\n" + " slice [long]: Round Robin scheduler slice\n" + "Returns: [int] 0 on success, throws an exception on failure\n" }, + + { "rrobin_global_get", + (PyCFunction)pyxc_rrobin_global_get, + METH_KEYWORDS, "\n" + "Get Round Robin scheduler settings\n" + "Returns [dict]:\n" + " slice [long]: Scheduler time slice.\n" }, + + { "evtchn_bind_interdomain", + (PyCFunction)pyxc_evtchn_bind_interdomain, + METH_VARARGS | METH_KEYWORDS, "\n" + "Open an event channel between two domains.\n" + " dom1 [int, SELF]: First domain to be connected.\n" + " dom2 [int, SELF]: Second domain to be connected.\n\n" + "Returns: [dict] dictionary is empty on failure.\n" + " port1 [int]: Port-id for endpoint at dom1.\n" + " port2 [int]: Port-id for endpoint at dom2.\n" }, + + { "evtchn_bind_virq", + (PyCFunction)pyxc_evtchn_bind_virq, + METH_VARARGS | METH_KEYWORDS, "\n" + "Bind an event channel to the specified VIRQ.\n" + " virq [int]: VIRQ to bind.\n\n" + "Returns: [int] Bound event-channel port.\n" }, + + { "evtchn_close", + (PyCFunction)pyxc_evtchn_close, + METH_VARARGS | METH_KEYWORDS, "\n" + "Close an event channel.\n" + " dom [int, SELF]: Dom-id of one endpoint of the channel.\n" + " port [int]: Port-id of one endpoint of the channel.\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "evtchn_send", + (PyCFunction)pyxc_evtchn_send, + METH_VARARGS | METH_KEYWORDS, "\n" + "Send an event along a locally-connected event channel.\n" + " port [int]: Port-id of a local channel endpoint.\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "evtchn_status", + (PyCFunction)pyxc_evtchn_status, + METH_VARARGS | METH_KEYWORDS, "\n" + "Query the status of an event channel.\n" + " dom [int, SELF]: Dom-id of one endpoint of the channel.\n" + " port [int]: Port-id of one endpoint of the channel.\n\n" + "Returns: [dict] dictionary is empty on failure.\n" + " status [str]: 'closed', 'unbound', 'interdomain', 'pirq'," + " or 'virq'.\n" + "The following are returned if 'status' is 'interdomain':\n" + " dom [int]: Dom-id of remote endpoint.\n" + " port [int]: Port-id of remote endpoint.\n" + "The following are returned if 'status' is 'pirq' or 'virq':\n" + " irq [int]: IRQ number.\n" }, + + { "physdev_pci_access_modify", + (PyCFunction)pyxc_physdev_pci_access_modify, + METH_VARARGS | METH_KEYWORDS, "\n" + "Allow a domain access to a PCI device\n" + " dom [int]: Identifier of domain to be allowed access.\n" + " bus [int]: PCI bus\n" + " dev [int]: PCI slot\n" + " func [int]: PCI function\n" + " enable [int]: Non-zero means enable access; else disable access\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "readconsolering", + (PyCFunction)pyxc_readconsolering, + METH_VARARGS | METH_KEYWORDS, "\n" + "Read Xen's console ring.\n" + " clear [int, 0]: Bool - clear the ring after reading from it?\n\n" + "Returns: [str] string is empty on failure.\n" }, + + { "physinfo", + (PyCFunction)pyxc_physinfo, + METH_VARARGS, "\n" + "Get information about the physical host machine\n" + "Returns [dict]: information about the hardware" + " [None]: on failure.\n" }, + + { "shadow_control", + (PyCFunction)pyxc_shadow_control, + METH_VARARGS | METH_KEYWORDS, "\n" + "Set parameter for shadow pagetable interface\n" + " dom [int]: Identifier of domain.\n" + " op [int, 0]: operation\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "domain_setname", + (PyCFunction)pyxc_domain_setname, + METH_VARARGS | METH_KEYWORDS, "\n" + "Set domain informative textual name\n" + " dom [int]: Identifier of domain.\n" + " name [str]: Text string.\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "domain_setmaxmem", + (PyCFunction)pyxc_domain_setname, + METH_VARARGS | METH_KEYWORDS, "\n" + "Set a domain's memory limit\n" + " dom [int]: Identifier of domain.\n" + " max_memkb [long]: .\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { NULL, NULL, 0, NULL } +}; + + +/* + * Definitions for the 'Xc' module wrapper. + */ + +staticforward PyTypeObject PyXcType; + +static PyObject *PyXc_new(PyObject *self, PyObject *args) +{ + XcObject *xc; + + if ( !PyArg_ParseTuple(args, ":new") ) + return NULL; + + xc = PyObject_New(XcObject, &PyXcType); + + if ( (xc->xc_handle = xc_interface_open()) == -1 ) + { + PyObject_Del((PyObject *)xc); + return PyErr_SetFromErrno(xc_error); + } + + return (PyObject *)xc; +} + +static PyObject *PyXc_getattr(PyObject *obj, char *name) +{ + return Py_FindMethod(pyxc_methods, obj, name); +} + +static void PyXc_dealloc(PyObject *self) +{ + XcObject *xc = (XcObject *)self; + (void)xc_interface_close(xc->xc_handle); + PyObject_Del(self); +} + +static PyTypeObject PyXcType = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "Xc", + sizeof(XcObject), + 0, + PyXc_dealloc, /* tp_dealloc */ + NULL, /* tp_print */ + PyXc_getattr, /* tp_getattr */ + NULL, /* tp_setattr */ + NULL, /* tp_compare */ + NULL, /* tp_repr */ + NULL, /* tp_as_number */ + NULL, /* tp_as_sequence */ + NULL, /* tp_as_mapping */ + NULL /* tp_hash */ +}; + +static PyMethodDef PyXc_methods[] = { + { "new", PyXc_new, METH_VARARGS, "Create a new " XENPKG " object." }, + { NULL, NULL, 0, NULL } +}; + +PyMODINIT_FUNC initxc(void) +{ + PyObject *m, *d; + + m = Py_InitModule(XENPKG, PyXc_methods); + + d = PyModule_GetDict(m); + xc_error = PyErr_NewException(XENPKG ".error", NULL, NULL); + PyDict_SetItemString(d, "error", xc_error); + + zero = PyInt_FromLong(0); +} diff --git a/tools/python/xen/ext/xu/__init__.py b/tools/python/xen/ext/xu/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tools/python/xen/ext/xu/domain_controller.h b/tools/python/xen/ext/xu/domain_controller.h new file mode 100644 index 0000000000..76dd164fcb --- /dev/null +++ b/tools/python/xen/ext/xu/domain_controller.h @@ -0,0 +1,532 @@ +/****************************************************************************** + * domain_controller.h + * + * Interface to server controller (e.g., 'xend'). This header file defines the + * interface that is shared with guest OSes. + * + * Copyright (c) 2004, K A Fraser + */ + +#ifndef __DOMAIN_CONTROLLER_H__ +#define __DOMAIN_CONTROLLER_H__ + + +#ifndef BASIC_START_INFO +#error "Xen header file hypervisor-if.h must already be included here." +#endif + + +/* + * EXTENDED BOOTSTRAP STRUCTURE FOR NEW DOMAINS. + */ + +typedef struct { + BASIC_START_INFO; + u16 domain_controller_evtchn; /* 320 */ +} PACKED extended_start_info_t; /* 322 bytes */ +#define SIF_BLK_BE_DOMAIN (1<<4) /* Is this a block backend domain? */ +#define SIF_NET_BE_DOMAIN (1<<5) /* Is this a net backend domain? */ + + +/* + * Reason codes for SCHEDOP_shutdown. These are opaque to Xen but may be + * interpreted by control software to determine the appropriate action. These + * are only really advisories: the controller can actually do as it likes. + */ +#define SHUTDOWN_poweroff 0 /* Domain exited normally. Clean up and kill. */ +#define SHUTDOWN_reboot 1 /* Clean up, kill, and then restart. */ +#define SHUTDOWN_suspend 2 /* Clean up, save suspend info, kill. */ + + +/* + * CONTROLLER MESSAGING INTERFACE. + */ + +typedef struct { + u8 type; /* 0: echoed in response */ + u8 subtype; /* 1: echoed in response */ + u8 id; /* 2: echoed in response */ + u8 length; /* 3: number of bytes in 'msg' */ + u8 msg[60]; /* 4: type-specific message data */ +} PACKED control_msg_t; /* 64 bytes */ + +#define CONTROL_RING_SIZE 8 +typedef u32 CONTROL_RING_IDX; +#define MASK_CONTROL_IDX(_i) ((_i)&(CONTROL_RING_SIZE-1)) + +typedef struct { + control_msg_t tx_ring[CONTROL_RING_SIZE]; /* 0: guest -> controller */ + control_msg_t rx_ring[CONTROL_RING_SIZE]; /* 512: controller -> guest */ + CONTROL_RING_IDX tx_req_prod, tx_resp_prod; /* 1024, 1028 */ + CONTROL_RING_IDX rx_req_prod, rx_resp_prod; /* 1032, 1036 */ +} PACKED control_if_t; /* 1040 bytes */ + +/* + * Top-level command types. + */ +#define CMSG_CONSOLE 0 /* Console */ +#define CMSG_BLKIF_BE 1 /* Block-device backend */ +#define CMSG_BLKIF_FE 2 /* Block-device frontend */ +#define CMSG_NETIF_BE 3 /* Network-device backend */ +#define CMSG_NETIF_FE 4 /* Network-device frontend */ +#define CMSG_SHUTDOWN 6 /* Shutdown messages */ + + +/****************************************************************************** + * CONSOLE DEFINITIONS + */ + +/* + * Subtypes for console messages. + */ +#define CMSG_CONSOLE_DATA 0 + + +/****************************************************************************** + * BLOCK-INTERFACE FRONTEND DEFINITIONS + */ + +/* Messages from domain controller to guest. */ +#define CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED 0 + +/* Messages from guest to domain controller. */ +#define CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED 32 +#define CMSG_BLKIF_FE_INTERFACE_CONNECT 33 +#define CMSG_BLKIF_FE_INTERFACE_DISCONNECT 34 + +/* These are used by both front-end and back-end drivers. */ +#define blkif_vdev_t u16 +#define blkif_pdev_t u16 +#define blkif_sector_t u64 + +/* + * CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED: + * Notify a guest about a status change on one of its block interfaces. + * If the interface is DESTROYED or DOWN then the interface is disconnected: + * 1. The shared-memory frame is available for reuse. + * 2. Any unacknowledged messgaes pending on the interface were dropped. + */ +#define BLKIF_INTERFACE_STATUS_DESTROYED 0 /* Interface doesn't exist. */ +#define BLKIF_INTERFACE_STATUS_DISCONNECTED 1 /* Exists but is disconnected. */ +#define BLKIF_INTERFACE_STATUS_CONNECTED 2 /* Exists and is connected. */ +typedef struct { + u32 handle; /* 0 */ + u32 status; /* 4 */ + u16 evtchn; /* 8: (only if status == BLKIF_INTERFACE_STATUS_CONNECTED). */ +} PACKED blkif_fe_interface_status_changed_t; /* 10 bytes */ + +/* + * CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED: + * Notify the domain controller that the front-end driver is DOWN or UP. + * When the driver goes DOWN then the controller will send no more + * status-change notifications. When the driver comes UP then the controller + * will send a notification for each interface that currently exists. + * If the driver goes DOWN while interfaces are still UP, the domain + * will automatically take the interfaces DOWN. + */ +#define BLKIF_DRIVER_STATUS_DOWN 0 +#define BLKIF_DRIVER_STATUS_UP 1 +typedef struct { + /* IN */ + u32 status; /* 0: BLKIF_DRIVER_STATUS_??? */ + /* OUT */ + /* + * Tells driver how many interfaces it should expect to immediately + * receive notifications about. + */ + u32 nr_interfaces; /* 4 */ +} PACKED blkif_fe_driver_status_changed_t; /* 8 bytes */ + +/* + * CMSG_BLKIF_FE_INTERFACE_CONNECT: + * If successful, the domain controller will acknowledge with a + * STATUS_CONNECTED message. + */ +typedef struct { + u32 handle; /* 0 */ + u32 __pad; + memory_t shmem_frame; /* 8 */ + MEMORY_PADDING; +} PACKED blkif_fe_interface_connect_t; /* 16 bytes */ + +/* + * CMSG_BLKIF_FE_INTERFACE_DISCONNECT: + * If successful, the domain controller will acknowledge with a + * STATUS_DISCONNECTED message. + */ +typedef struct { + u32 handle; /* 0 */ +} PACKED blkif_fe_interface_disconnect_t; /* 4 bytes */ + + +/****************************************************************************** + * BLOCK-INTERFACE BACKEND DEFINITIONS + */ + +/* Messages from domain controller. */ +#define CMSG_BLKIF_BE_CREATE 0 /* Create a new block-device interface. */ +#define CMSG_BLKIF_BE_DESTROY 1 /* Destroy a block-device interface. */ +#define CMSG_BLKIF_BE_CONNECT 2 /* Connect i/f to remote driver. */ +#define CMSG_BLKIF_BE_DISCONNECT 3 /* Disconnect i/f from remote driver. */ +#define CMSG_BLKIF_BE_VBD_CREATE 4 /* Create a new VBD for an interface. */ +#define CMSG_BLKIF_BE_VBD_DESTROY 5 /* Delete a VBD from an interface. */ +#define CMSG_BLKIF_BE_VBD_GROW 6 /* Append an extent to a given VBD. */ +#define CMSG_BLKIF_BE_VBD_SHRINK 7 /* Remove last extent from a given VBD. */ + +/* Messages to domain controller. */ +#define CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED 32 + +/* + * Message request/response definitions for block-device messages. + */ + +typedef struct { + blkif_sector_t sector_start; /* 0 */ + blkif_sector_t sector_length; /* 8 */ + blkif_pdev_t device; /* 16 */ + u16 __pad; /* 18 */ +} PACKED blkif_extent_t; /* 20 bytes */ + +/* Non-specific 'okay' return. */ +#define BLKIF_BE_STATUS_OKAY 0 +/* Non-specific 'error' return. */ +#define BLKIF_BE_STATUS_ERROR 1 +/* The following are specific error returns. */ +#define BLKIF_BE_STATUS_INTERFACE_EXISTS 2 +#define BLKIF_BE_STATUS_INTERFACE_NOT_FOUND 3 +#define BLKIF_BE_STATUS_INTERFACE_CONNECTED 4 +#define BLKIF_BE_STATUS_VBD_EXISTS 5 +#define BLKIF_BE_STATUS_VBD_NOT_FOUND 6 +#define BLKIF_BE_STATUS_OUT_OF_MEMORY 7 +#define BLKIF_BE_STATUS_EXTENT_NOT_FOUND 8 +#define BLKIF_BE_STATUS_MAPPING_ERROR 9 + +/* This macro can be used to create an array of descriptive error strings. */ +#define BLKIF_BE_STATUS_ERRORS { \ + "Okay", \ + "Non-specific error", \ + "Interface already exists", \ + "Interface not found", \ + "Interface is still connected", \ + "VBD already exists", \ + "VBD not found", \ + "Out of memory", \ + "Extent not found for VBD", \ + "Could not map domain memory" } + +/* + * CMSG_BLKIF_BE_CREATE: + * When the driver sends a successful response then the interface is fully + * created. The controller will send a DOWN notification to the front-end + * driver. + */ +typedef struct { + /* IN */ + domid_t domid; /* 0: Domain attached to new interface. */ + u32 blkif_handle; /* 4: Domain-specific interface handle. */ + /* OUT */ + u32 status; /* 8 */ +} PACKED blkif_be_create_t; /* 12 bytes */ + +/* + * CMSG_BLKIF_BE_DESTROY: + * When the driver sends a successful response then the interface is fully + * torn down. The controller will send a DESTROYED notification to the + * front-end driver. + */ +typedef struct { + /* IN */ + domid_t domid; /* 0: Identify interface to be destroyed. */ + u32 blkif_handle; /* 4: ...ditto... */ + /* OUT */ + u32 status; /* 8 */ +} PACKED blkif_be_destroy_t; /* 12 bytes */ + +/* + * CMSG_BLKIF_BE_CONNECT: + * When the driver sends a successful response then the interface is fully + * connected. The controller will send a CONNECTED notification to the + * front-end driver. + */ +typedef struct { + /* IN */ + domid_t domid; /* 0: Domain attached to new interface. */ + u32 blkif_handle; /* 4: Domain-specific interface handle. */ + memory_t shmem_frame; /* 8: Page cont. shared comms window. */ + MEMORY_PADDING; + u32 evtchn; /* 16: Event channel for notifications. */ + /* OUT */ + u32 status; /* 20 */ +} PACKED blkif_be_connect_t; /* 24 bytes */ + +/* + * CMSG_BLKIF_BE_DISCONNECT: + * When the driver sends a successful response then the interface is fully + * disconnected. The controller will send a DOWN notification to the front-end + * driver. + */ +typedef struct { + /* IN */ + domid_t domid; /* 0: Domain attached to new interface. */ + u32 blkif_handle; /* 4: Domain-specific interface handle. */ + /* OUT */ + u32 status; /* 8 */ +} PACKED blkif_be_disconnect_t; /* 12 bytes */ + +/* CMSG_BLKIF_BE_VBD_CREATE */ +typedef struct { + /* IN */ + domid_t domid; /* 0: Identify blkdev interface. */ + u32 blkif_handle; /* 4: ...ditto... */ + blkif_vdev_t vdevice; /* 8: Interface-specific id for this VBD. */ + u16 readonly; /* 10: Non-zero -> VBD isn't writeable. */ + /* OUT */ + u32 status; /* 12 */ +} PACKED blkif_be_vbd_create_t; /* 16 bytes */ + +/* CMSG_BLKIF_BE_VBD_DESTROY */ +typedef struct { + /* IN */ + domid_t domid; /* 0: Identify blkdev interface. */ + u32 blkif_handle; /* 4: ...ditto... */ + blkif_vdev_t vdevice; /* 8: Interface-specific id of the VBD. */ + u16 __pad; /* 10 */ + /* OUT */ + u32 status; /* 12 */ +} PACKED blkif_be_vbd_destroy_t; /* 16 bytes */ + +/* CMSG_BLKIF_BE_VBD_GROW */ +typedef struct { + /* IN */ + domid_t domid; /* 0: Identify blkdev interface. */ + u32 blkif_handle; /* 4: ...ditto... */ + blkif_extent_t extent; /* 8: Physical extent to append to VBD. */ + blkif_vdev_t vdevice; /* 28: Interface-specific id of the VBD. */ + u16 __pad; /* 30 */ + /* OUT */ + u32 status; /* 32 */ +} PACKED blkif_be_vbd_grow_t; /* 36 bytes */ + +/* CMSG_BLKIF_BE_VBD_SHRINK */ +typedef struct { + /* IN */ + domid_t domid; /* 0: Identify blkdev interface. */ + u32 blkif_handle; /* 4: ...ditto... */ + blkif_vdev_t vdevice; /* 8: Interface-specific id of the VBD. */ + u16 __pad; /* 10 */ + /* OUT */ + u32 status; /* 12 */ +} PACKED blkif_be_vbd_shrink_t; /* 16 bytes */ + +/* + * CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED: + * Notify the domain controller that the back-end driver is DOWN or UP. + * If the driver goes DOWN while interfaces are still UP, the controller + * will automatically send DOWN notifications. + */ +typedef struct { + u32 status; /* 0: BLKIF_DRIVER_STATUS_??? */ +} PACKED blkif_be_driver_status_changed_t; /* 4 bytes */ + + +/****************************************************************************** + * NETWORK-INTERFACE FRONTEND DEFINITIONS + */ + +/* Messages from domain controller to guest. */ +#define CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED 0 + +/* Messages from guest to domain controller. */ +#define CMSG_NETIF_FE_DRIVER_STATUS_CHANGED 32 +#define CMSG_NETIF_FE_INTERFACE_CONNECT 33 +#define CMSG_NETIF_FE_INTERFACE_DISCONNECT 34 + +/* + * CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED: + * Notify a guest about a status change on one of its network interfaces. + * If the interface is DESTROYED or DOWN then the interface is disconnected: + * 1. The shared-memory frame is available for reuse. + * 2. Any unacknowledged messgaes pending on the interface were dropped. + */ +#define NETIF_INTERFACE_STATUS_DESTROYED 0 /* Interface doesn't exist. */ +#define NETIF_INTERFACE_STATUS_DISCONNECTED 1 /* Exists but is disconnected. */ +#define NETIF_INTERFACE_STATUS_CONNECTED 2 /* Exists and is connected. */ +typedef struct { + u32 handle; /* 0 */ + u32 status; /* 4 */ + u16 evtchn; /* 8: status == NETIF_INTERFACE_STATUS_CONNECTED */ + u8 mac[6]; /* 10: status == NETIF_INTERFACE_STATUS_CONNECTED */ +} PACKED netif_fe_interface_status_changed_t; /* 16 bytes */ + +/* + * CMSG_NETIF_FE_DRIVER_STATUS_CHANGED: + * Notify the domain controller that the front-end driver is DOWN or UP. + * When the driver goes DOWN then the controller will send no more + * status-change notifications. When the driver comes UP then the controller + * will send a notification for each interface that currently exists. + * If the driver goes DOWN while interfaces are still UP, the domain + * will automatically take the interfaces DOWN. + */ +#define NETIF_DRIVER_STATUS_DOWN 0 +#define NETIF_DRIVER_STATUS_UP 1 +typedef struct { + /* IN */ + u32 status; /* 0: NETIF_DRIVER_STATUS_??? */ + /* OUT */ + /* + * Tells driver how many interfaces it should expect to immediately + * receive notifications about. + */ + u32 nr_interfaces; /* 4 */ +} PACKED netif_fe_driver_status_changed_t; /* 8 bytes */ + +/* + * CMSG_NETIF_FE_INTERFACE_CONNECT: + * If successful, the domain controller will acknowledge with a + * STATUS_CONNECTED message. + */ +typedef struct { + u32 handle; /* 0 */ + u32 __pad; /* 4 */ + memory_t tx_shmem_frame; /* 8 */ + MEMORY_PADDING; + memory_t rx_shmem_frame; /* 16 */ + MEMORY_PADDING; +} PACKED netif_fe_interface_connect_t; /* 24 bytes */ + +/* + * CMSG_NETIF_FE_INTERFACE_DISCONNECT: + * If successful, the domain controller will acknowledge with a + * STATUS_DISCONNECTED message. + */ +typedef struct { + u32 handle; /* 0 */ +} PACKED netif_fe_interface_disconnect_t; /* 4 bytes */ + + +/****************************************************************************** + * NETWORK-INTERFACE BACKEND DEFINITIONS + */ + +/* Messages from domain controller. */ +#define CMSG_NETIF_BE_CREATE 0 /* Create a new net-device interface. */ +#define CMSG_NETIF_BE_DESTROY 1 /* Destroy a net-device interface. */ +#define CMSG_NETIF_BE_CONNECT 2 /* Connect i/f to remote driver. */ +#define CMSG_NETIF_BE_DISCONNECT 3 /* Disconnect i/f from remote driver. */ + +/* Messages to domain controller. */ +#define CMSG_NETIF_BE_DRIVER_STATUS_CHANGED 32 + +/* + * Message request/response definitions for net-device messages. + */ + +/* Non-specific 'okay' return. */ +#define NETIF_BE_STATUS_OKAY 0 +/* Non-specific 'error' return. */ +#define NETIF_BE_STATUS_ERROR 1 +/* The following are specific error returns. */ +#define NETIF_BE_STATUS_INTERFACE_EXISTS 2 +#define NETIF_BE_STATUS_INTERFACE_NOT_FOUND 3 +#define NETIF_BE_STATUS_INTERFACE_CONNECTED 4 +#define NETIF_BE_STATUS_OUT_OF_MEMORY 5 +#define NETIF_BE_STATUS_MAPPING_ERROR 6 + +/* This macro can be used to create an array of descriptive error strings. */ +#define NETIF_BE_STATUS_ERRORS { \ + "Okay", \ + "Non-specific error", \ + "Interface already exists", \ + "Interface not found", \ + "Interface is still connected", \ + "Out of memory", \ + "Could not map domain memory" } + +/* + * CMSG_NETIF_BE_CREATE: + * When the driver sends a successful response then the interface is fully + * created. The controller will send a DOWN notification to the front-end + * driver. + */ +typedef struct { + /* IN */ + domid_t domid; /* 0: Domain attached to new interface. */ + u32 netif_handle; /* 4: Domain-specific interface handle. */ + u8 mac[6]; /* 8 */ + u16 __pad; /* 14 */ + /* OUT */ + u32 status; /* 16 */ +} PACKED netif_be_create_t; /* 20 bytes */ + +/* + * CMSG_NETIF_BE_DESTROY: + * When the driver sends a successful response then the interface is fully + * torn down. The controller will send a DESTROYED notification to the + * front-end driver. + */ +typedef struct { + /* IN */ + domid_t domid; /* 0: Identify interface to be destroyed. */ + u32 netif_handle; /* 4: ...ditto... */ + /* OUT */ + u32 status; /* 8 */ +} PACKED netif_be_destroy_t; /* 12 bytes */ + +/* + * CMSG_NETIF_BE_CONNECT: + * When the driver sends a successful response then the interface is fully + * connected. The controller will send a CONNECTED notification to the + * front-end driver. + */ +typedef struct { + /* IN */ + domid_t domid; /* 0: Domain attached to new interface. */ + u32 netif_handle; /* 4: Domain-specific interface handle. */ + memory_t tx_shmem_frame; /* 8: Page cont. tx shared comms window. */ + MEMORY_PADDING; + memory_t rx_shmem_frame; /* 16: Page cont. rx shared comms window. */ + MEMORY_PADDING; + u16 evtchn; /* 24: Event channel for notifications. */ + u16 __pad; /* 26 */ + /* OUT */ + u32 status; /* 28 */ +} PACKED netif_be_connect_t; /* 32 bytes */ + +/* + * CMSG_NETIF_BE_DISCONNECT: + * When the driver sends a successful response then the interface is fully + * disconnected. The controller will send a DOWN notification to the front-end + * driver. + */ +typedef struct { + /* IN */ + domid_t domid; /* 0: Domain attached to new interface. */ + u32 netif_handle; /* 4: Domain-specific interface handle. */ + /* OUT */ + u32 status; /* 8 */ +} PACKED netif_be_disconnect_t; /* 12 bytes */ + +/* + * CMSG_NETIF_BE_DRIVER_STATUS_CHANGED: + * Notify the domain controller that the back-end driver is DOWN or UP. + * If the driver goes DOWN while interfaces are still UP, the domain + * will automatically send DOWN notifications. + */ +typedef struct { + u32 status; /* 0: NETIF_DRIVER_STATUS_??? */ +} PACKED netif_be_driver_status_changed_t; /* 4 bytes */ + + +/****************************************************************************** + * SHUTDOWN DEFINITIONS + */ + +/* + * Subtypes for shutdown messages. + */ +#define CMSG_SHUTDOWN_POWEROFF 0 /* Clean shutdown (SHUTDOWN_poweroff). */ +#define CMSG_SHUTDOWN_REBOOT 1 /* Clean shutdown (SHUTDOWN_reboot). */ +#define CMSG_SHUTDOWN_SUSPEND 2 /* Create suspend info, then */ + /* SHUTDOWN_suspend. */ + +#endif /* __DOMAIN_CONTROLLER_H__ */ diff --git a/tools/python/xen/ext/xu/xu.c b/tools/python/xen/ext/xu/xu.c new file mode 100644 index 0000000000..48c975912d --- /dev/null +++ b/tools/python/xen/ext/xu/xu.c @@ -0,0 +1,1386 @@ +/****************************************************************************** + * utils.c + * + * Copyright (c) 2004, K A Fraser + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "domain_controller.h" + +#include + +#define XENPKG "xen.ext.xu" + +/* Needed for Python versions earlier than 2.3. */ +#ifndef PyMODINIT_FUNC +#define PyMODINIT_FUNC DL_EXPORT(void) +#endif + +/* NB. The following should be kept in sync with the kernel's evtchn driver. */ +#define EVTCHN_DEV_NAME "/dev/xen/evtchn" +#define EVTCHN_DEV_MAJOR 10 +#define EVTCHN_DEV_MINOR 200 +#define PORT_NORMAL 0x0000 /* A standard event notification. */ +#define PORT_EXCEPTION 0x8000 /* An exceptional notification. */ +#define PORTIDX_MASK 0x7fff /* Strip subtype to obtain port index. */ +/* /dev/xen/evtchn ioctls: */ +/* EVTCHN_RESET: Clear and reinit the event buffer. Clear error condition. */ +#define EVTCHN_RESET _IO('E', 1) +/* EVTCHN_BIND: Bind to teh specified event-channel port. */ +#define EVTCHN_BIND _IO('E', 2) +/* EVTCHN_UNBIND: Unbind from the specified event-channel port. */ +#define EVTCHN_UNBIND _IO('E', 3) + +/* Size of a machine page frame. */ +#define PAGE_SIZE 4096 + + +/* + * *********************** NOTIFIER *********************** + */ + +typedef struct { + PyObject_HEAD; + int evtchn_fd; +} xu_notifier_object; + +static PyObject *xu_notifier_read(PyObject *self, PyObject *args) +{ + xu_notifier_object *xun = (xu_notifier_object *)self; + u16 v; + int bytes; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + while ( (bytes = read(xun->evtchn_fd, &v, sizeof(v))) == -1 ) + { + if ( errno == EINTR ) + continue; + if ( errno == EAGAIN ) + goto none; + return PyErr_SetFromErrno(PyExc_IOError); + } + + if ( bytes == sizeof(v) ) + return Py_BuildValue("(i,i)", v&PORTIDX_MASK, v&~PORTIDX_MASK); + + none: + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject *xu_notifier_unmask(PyObject *self, PyObject *args) +{ + xu_notifier_object *xun = (xu_notifier_object *)self; + u16 v; + int idx; + + if ( !PyArg_ParseTuple(args, "i", &idx) ) + return NULL; + + v = (u16)idx; + + (void)write(xun->evtchn_fd, &v, sizeof(v)); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject *xu_notifier_bind(PyObject *self, PyObject *args) +{ + xu_notifier_object *xun = (xu_notifier_object *)self; + int idx; + + if ( !PyArg_ParseTuple(args, "i", &idx) ) + return NULL; + + if ( ioctl(xun->evtchn_fd, EVTCHN_BIND, idx) != 0 ) + return PyErr_SetFromErrno(PyExc_IOError); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject *xu_notifier_unbind(PyObject *self, PyObject *args) +{ + xu_notifier_object *xun = (xu_notifier_object *)self; + int idx; + + if ( !PyArg_ParseTuple(args, "i", &idx) ) + return NULL; + + if ( ioctl(xun->evtchn_fd, EVTCHN_UNBIND, idx) != 0 ) + return PyErr_SetFromErrno(PyExc_IOError); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject *xu_notifier_fileno(PyObject *self, PyObject *args) +{ + xu_notifier_object *xun = (xu_notifier_object *)self; + return PyInt_FromLong(xun->evtchn_fd); +} + +static PyMethodDef xu_notifier_methods[] = { + { "read", + (PyCFunction)xu_notifier_read, + METH_VARARGS, + "Read a (@port, @type) pair.\n" }, + + { "unmask", + (PyCFunction)xu_notifier_unmask, + METH_VARARGS, + "Unmask notifications for a @port.\n" }, + + { "bind", + (PyCFunction)xu_notifier_bind, + METH_VARARGS, + "Get notifications for a @port.\n" }, + + { "unbind", + (PyCFunction)xu_notifier_unbind, + METH_VARARGS, + "No longer get notifications for a @port.\n" }, + + { "fileno", + (PyCFunction)xu_notifier_fileno, + METH_VARARGS, + "Return the file descriptor for the notification channel.\n" }, + + { NULL, NULL, 0, NULL } +}; + +staticforward PyTypeObject xu_notifier_type; + +static PyObject *xu_notifier_new(PyObject *self, PyObject *args) +{ + xu_notifier_object *xun; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + xun = PyObject_New(xu_notifier_object, &xu_notifier_type); + + reopen: + xun->evtchn_fd = open(EVTCHN_DEV_NAME, O_NONBLOCK|O_RDWR); + if ( xun->evtchn_fd == -1 ) + { + if ( (errno == ENOENT) && + ((mkdir("/dev/xen", 0755) == 0) || (errno == EEXIST)) && + (mknod(EVTCHN_DEV_NAME, S_IFCHR|0600, + (EVTCHN_DEV_MAJOR << 8) | EVTCHN_DEV_MINOR) == 0) ) + goto reopen; + PyObject_Del((PyObject *)xun); + return PyErr_SetFromErrno(PyExc_IOError); + } + + return (PyObject *)xun; +} + +static PyObject *xu_notifier_getattr(PyObject *obj, char *name) +{ + if ( strcmp(name, "EXCEPTION") == 0 ) + return PyInt_FromLong(PORT_EXCEPTION); + if ( strcmp(name, "NORMAL") == 0 ) + return PyInt_FromLong(PORT_NORMAL); + return Py_FindMethod(xu_notifier_methods, obj, name); +} + +static void xu_notifier_dealloc(PyObject *self) +{ + xu_notifier_object *xun = (xu_notifier_object *)self; + (void)close(xun->evtchn_fd); + PyObject_Del(self); +} + +static PyTypeObject xu_notifier_type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "notifier", + sizeof(xu_notifier_object), + 0, + xu_notifier_dealloc, /* tp_dealloc */ + NULL, /* tp_print */ + xu_notifier_getattr, /* tp_getattr */ + NULL, /* tp_setattr */ + NULL, /* tp_compare */ + NULL, /* tp_repr */ + NULL, /* tp_as_number */ + NULL, /* tp_as_sequence */ + NULL, /* tp_as_mapping */ + NULL /* tp_hash */ +}; + + + +/* + * *********************** MESSAGE *********************** + */ + +#define TYPE(_x,_y) (((_x)<<8)|(_y)) +#define P2C(_struct, _field, _ctype) \ + do { \ + PyObject *obj; \ + if ( (obj = PyDict_GetItemString(payload, #_field)) != NULL ) \ + { \ + if ( PyInt_Check(obj) ) \ + { \ + ((_struct *)&xum->msg.msg[0])->_field = \ + (_ctype)PyInt_AsLong(obj); \ + dict_items_parsed++; \ + } \ + else if ( PyLong_Check(obj) ) \ + { \ + ((_struct *)&xum->msg.msg[0])->_field = \ + (_ctype)PyLong_AsUnsignedLongLong(obj); \ + dict_items_parsed++; \ + } \ + } \ + xum->msg.length = sizeof(_struct); \ + } while ( 0 ) +#define C2P(_struct, _field, _pytype, _ctype) \ + do { \ + PyObject *obj = Py ## _pytype ## _From ## _ctype \ + (((_struct *)&xum->msg.msg[0])->_field); \ + if ( dict == NULL ) dict = PyDict_New(); \ + PyDict_SetItemString(dict, #_field, obj); \ + } while ( 0 ) + +typedef struct { + PyObject_HEAD; + control_msg_t msg; +} xu_message_object; + +static PyObject *xu_message_append_payload(PyObject *self, PyObject *args) +{ + xu_message_object *xum = (xu_message_object *)self; + char *str; + int len; + + if ( !PyArg_ParseTuple(args, "s#", &str, &len) ) + return NULL; + + if ( (len + xum->msg.length) > sizeof(xum->msg.msg) ) + { + PyErr_SetString(PyExc_RuntimeError, "out of space in control message"); + return NULL; + } + + memcpy(&xum->msg.msg[xum->msg.length], str, len); + xum->msg.length += len; + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject *xu_message_set_response_fields(PyObject *self, PyObject *args) +{ + xu_message_object *xum = (xu_message_object *)self; + PyObject *payload; + int dict_items_parsed = 0; + + if ( !PyArg_ParseTuple(args, "O", &payload) ) + return NULL; + + if ( !PyDict_Check(payload) ) + { + PyErr_SetString(PyExc_TypeError, "payload is not a dictionary"); + return NULL; + } + + switch ( TYPE(xum->msg.type, xum->msg.subtype) ) + { + case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED): + P2C(blkif_fe_driver_status_changed_t, nr_interfaces, u32); + break; + case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED): + P2C(netif_fe_driver_status_changed_t, nr_interfaces, u32); + break; + } + + if ( dict_items_parsed != PyDict_Size(payload) ) + { + PyErr_SetString(PyExc_TypeError, "payload contains bad items"); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject *xu_message_get_payload(PyObject *self, PyObject *args) +{ + xu_message_object *xum = (xu_message_object *)self; + PyObject *dict = NULL; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + switch ( TYPE(xum->msg.type, xum->msg.subtype) ) + { + case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED): + C2P(blkif_fe_interface_status_changed_t, handle, Int, Long); + C2P(blkif_fe_interface_status_changed_t, status, Int, Long); + C2P(blkif_fe_interface_status_changed_t, evtchn, Int, Long); + return dict; + case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED): + C2P(blkif_fe_driver_status_changed_t, status, Int, Long); + return dict; + case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_CONNECT): + C2P(blkif_fe_interface_connect_t, handle, Int, Long); + C2P(blkif_fe_interface_connect_t, shmem_frame, Int, Long); + return dict; + case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_DISCONNECT): + C2P(blkif_fe_interface_disconnect_t, handle, Int, Long); + return dict; + case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_CREATE): + C2P(blkif_be_create_t, domid, Int, Long); + C2P(blkif_be_create_t, blkif_handle, Int, Long); + C2P(blkif_be_create_t, status, Int, Long); + return dict; + case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DESTROY): + C2P(blkif_be_destroy_t, domid, Int, Long); + C2P(blkif_be_destroy_t, blkif_handle, Int, Long); + C2P(blkif_be_destroy_t, status, Int, Long); + return dict; + case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_CONNECT): + C2P(blkif_be_connect_t, domid, Int, Long); + C2P(blkif_be_connect_t, blkif_handle, Int, Long); + C2P(blkif_be_connect_t, shmem_frame, Int, Long); + C2P(blkif_be_connect_t, evtchn, Int, Long); + C2P(blkif_be_connect_t, status, Int, Long); + return dict; + case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DISCONNECT): + C2P(blkif_be_disconnect_t, domid, Int, Long); + C2P(blkif_be_disconnect_t, blkif_handle, Int, Long); + C2P(blkif_be_disconnect_t, status, Int, Long); + return dict; + case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_CREATE): + C2P(blkif_be_vbd_create_t, domid, Int, Long); + C2P(blkif_be_vbd_create_t, blkif_handle, Int, Long); + C2P(blkif_be_vbd_create_t, vdevice, Int, Long); + C2P(blkif_be_vbd_create_t, readonly, Int, Long); + C2P(blkif_be_vbd_create_t, status, Int, Long); + return dict; + case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_DESTROY): + C2P(blkif_be_vbd_destroy_t, domid, Int, Long); + C2P(blkif_be_vbd_destroy_t, blkif_handle, Int, Long); + C2P(blkif_be_vbd_destroy_t, vdevice, Int, Long); + C2P(blkif_be_vbd_destroy_t, status, Int, Long); + return dict; + case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_GROW): + C2P(blkif_be_vbd_grow_t, domid, Int, Long); + C2P(blkif_be_vbd_grow_t, blkif_handle, Int, Long); + C2P(blkif_be_vbd_grow_t, vdevice, Int, Long); + C2P(blkif_be_vbd_grow_t, extent.sector_start, + Long, UnsignedLongLong); + C2P(blkif_be_vbd_grow_t, extent.sector_length, + Long, UnsignedLongLong); + C2P(blkif_be_vbd_grow_t, extent.device, Int, Long); + C2P(blkif_be_vbd_grow_t, status, Int, Long); + return dict; + case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_SHRINK): + C2P(blkif_be_vbd_shrink_t, domid, Int, Long); + C2P(blkif_be_vbd_shrink_t, blkif_handle, Int, Long); + C2P(blkif_be_vbd_shrink_t, vdevice, Int, Long); + C2P(blkif_be_vbd_shrink_t, status, Int, Long); + return dict; + case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED): + C2P(blkif_be_driver_status_changed_t, status, Int, Long); + return dict; + case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED): + C2P(netif_fe_interface_status_changed_t, handle, Int, Long); + C2P(netif_fe_interface_status_changed_t, status, Int, Long); + C2P(netif_fe_interface_status_changed_t, evtchn, Int, Long); + return dict; + case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED): + C2P(netif_fe_driver_status_changed_t, status, Int, Long); + C2P(netif_fe_driver_status_changed_t, nr_interfaces, Int, Long); + return dict; + case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_CONNECT): + C2P(netif_fe_interface_connect_t, handle, Int, Long); + C2P(netif_fe_interface_connect_t, tx_shmem_frame, Int, Long); + C2P(netif_fe_interface_connect_t, rx_shmem_frame, Int, Long); + return dict; + case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_DISCONNECT): + C2P(netif_fe_interface_disconnect_t, handle, Int, Long); + return dict; + case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_CREATE): + C2P(netif_be_create_t, domid, Int, Long); + C2P(netif_be_create_t, netif_handle, Int, Long); + C2P(netif_be_create_t, status, Int, Long); + return dict; + case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DESTROY): + C2P(netif_be_destroy_t, domid, Int, Long); + C2P(netif_be_destroy_t, netif_handle, Int, Long); + C2P(netif_be_destroy_t, status, Int, Long); + return dict; + case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_CONNECT): + C2P(netif_be_connect_t, domid, Int, Long); + C2P(netif_be_connect_t, netif_handle, Int, Long); + C2P(netif_be_connect_t, tx_shmem_frame, Int, Long); + C2P(netif_be_connect_t, rx_shmem_frame, Int, Long); + C2P(netif_be_connect_t, evtchn, Int, Long); + C2P(netif_be_connect_t, status, Int, Long); + return dict; + case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DISCONNECT): + C2P(netif_be_disconnect_t, domid, Int, Long); + C2P(netif_be_disconnect_t, netif_handle, Int, Long); + C2P(netif_be_disconnect_t, status, Int, Long); + return dict; + case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DRIVER_STATUS_CHANGED): + C2P(netif_be_driver_status_changed_t, status, Int, Long); + return dict; + } + + return PyString_FromStringAndSize(xum->msg.msg, xum->msg.length); +} + +static PyObject *xu_message_get_header(PyObject *self, PyObject *args) +{ + xu_message_object *xum = (xu_message_object *)self; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + return Py_BuildValue("{s:i,s:i,s:i}", + "type", xum->msg.type, + "subtype", xum->msg.subtype, + "id", xum->msg.id); +} + +static PyMethodDef xu_message_methods[] = { + { "append_payload", + (PyCFunction)xu_message_append_payload, + METH_VARARGS, + "Append @str to the message payload.\n" }, + + { "set_response_fields", + (PyCFunction)xu_message_set_response_fields, + METH_VARARGS, + "Fill in the response fields in a message that was passed to us.\n" }, + + { "get_payload", + (PyCFunction)xu_message_get_payload, + METH_VARARGS, + "Return the message payload in string form.\n" }, + + { "get_header", + (PyCFunction)xu_message_get_header, + METH_VARARGS, + "Returns a dictionary of values for @type, @subtype, and @id.\n" }, + + { NULL, NULL, 0, NULL } +}; + +staticforward PyTypeObject xu_message_type; + +static PyObject *xu_message_new(PyObject *self, PyObject *args) +{ + xu_message_object *xum; + int type, subtype, id, dict_items_parsed = 0; + PyObject *payload = NULL; + + if ( !PyArg_ParseTuple(args, "iii|O", &type, &subtype, &id, &payload) ) + return NULL; + + xum = PyObject_New(xu_message_object, &xu_message_type); + + xum->msg.type = type; + xum->msg.subtype = subtype; + xum->msg.id = id; + xum->msg.length = 0; + + if ( payload == NULL ) + return (PyObject *)xum; + + if ( !PyDict_Check(payload) ) + { + PyErr_SetString(PyExc_TypeError, "payload is not a dictionary"); + PyObject_Del((PyObject *)xum); + return NULL; + } + + switch ( TYPE(type, subtype) ) + { + case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED): + P2C(blkif_fe_interface_status_changed_t, handle, u32); + P2C(blkif_fe_interface_status_changed_t, status, u32); + P2C(blkif_fe_interface_status_changed_t, evtchn, u16); + break; + case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_CREATE): + P2C(blkif_be_create_t, domid, u32); + P2C(blkif_be_create_t, blkif_handle, u32); + break; + case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DESTROY): + P2C(blkif_be_destroy_t, domid, u32); + P2C(blkif_be_destroy_t, blkif_handle, u32); + break; + case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_CONNECT): + P2C(blkif_be_connect_t, domid, u32); + P2C(blkif_be_connect_t, blkif_handle, u32); + P2C(blkif_be_connect_t, shmem_frame, memory_t); + P2C(blkif_be_connect_t, evtchn, u16); + break; + case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DISCONNECT): + P2C(blkif_be_disconnect_t, domid, u32); + P2C(blkif_be_disconnect_t, blkif_handle, u32); + break; + case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_CREATE): + P2C(blkif_be_vbd_create_t, domid, u32); + P2C(blkif_be_vbd_create_t, blkif_handle, u32); + P2C(blkif_be_vbd_create_t, vdevice, blkif_vdev_t); + P2C(blkif_be_vbd_create_t, readonly, u16); + break; + case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_DESTROY): + P2C(blkif_be_vbd_destroy_t, domid, u32); + P2C(blkif_be_vbd_destroy_t, blkif_handle, u32); + P2C(blkif_be_vbd_destroy_t, vdevice, blkif_vdev_t); + break; + case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_GROW): + P2C(blkif_be_vbd_grow_t, domid, u32); + P2C(blkif_be_vbd_grow_t, blkif_handle, u32); + P2C(blkif_be_vbd_grow_t, vdevice, blkif_vdev_t); + P2C(blkif_be_vbd_grow_t, extent.sector_start, blkif_sector_t); + P2C(blkif_be_vbd_grow_t, extent.sector_length, blkif_sector_t); + P2C(blkif_be_vbd_grow_t, extent.device, blkif_pdev_t); + break; + case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_SHRINK): + P2C(blkif_be_vbd_shrink_t, domid, u32); + P2C(blkif_be_vbd_shrink_t, blkif_handle, u32); + P2C(blkif_be_vbd_shrink_t, vdevice, blkif_vdev_t); + break; + case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED): + P2C(netif_fe_interface_status_changed_t, handle, u32); + P2C(netif_fe_interface_status_changed_t, status, u32); + P2C(netif_fe_interface_status_changed_t, evtchn, u16); + P2C(netif_fe_interface_status_changed_t, mac[0], u8); + P2C(netif_fe_interface_status_changed_t, mac[1], u8); + P2C(netif_fe_interface_status_changed_t, mac[2], u8); + P2C(netif_fe_interface_status_changed_t, mac[3], u8); + P2C(netif_fe_interface_status_changed_t, mac[4], u8); + P2C(netif_fe_interface_status_changed_t, mac[5], u8); + break; + case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_CREATE): + P2C(netif_be_create_t, domid, u32); + P2C(netif_be_create_t, netif_handle, u32); + P2C(netif_be_create_t, mac[0], u8); + P2C(netif_be_create_t, mac[1], u8); + P2C(netif_be_create_t, mac[2], u8); + P2C(netif_be_create_t, mac[3], u8); + P2C(netif_be_create_t, mac[4], u8); + P2C(netif_be_create_t, mac[5], u8); + break; + case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DESTROY): + P2C(netif_be_destroy_t, domid, u32); + P2C(netif_be_destroy_t, netif_handle, u32); + break; + case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_CONNECT): + P2C(netif_be_connect_t, domid, u32); + P2C(netif_be_connect_t, netif_handle, u32); + P2C(netif_be_connect_t, tx_shmem_frame, memory_t); + P2C(netif_be_connect_t, rx_shmem_frame, memory_t); + P2C(netif_be_connect_t, evtchn, u16); + break; + case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DISCONNECT): + P2C(netif_be_disconnect_t, domid, u32); + P2C(netif_be_disconnect_t, netif_handle, u32); + break; + case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED): + P2C(netif_fe_driver_status_changed_t, status, u32); + P2C(netif_fe_driver_status_changed_t, nr_interfaces, u32); + break; + } + + if ( dict_items_parsed != PyDict_Size(payload) ) + { + PyErr_SetString(PyExc_TypeError, "payload contains bad items"); + PyObject_Del((PyObject *)xum); + return NULL; + } + + return (PyObject *)xum; +} + +static PyObject *xu_message_getattr(PyObject *obj, char *name) +{ + xu_message_object *xum; + if ( strcmp(name, "MAX_PAYLOAD") == 0 ) + return PyInt_FromLong(sizeof(xum->msg.msg)); + return Py_FindMethod(xu_message_methods, obj, name); +} + +static void xu_message_dealloc(PyObject *self) +{ + PyObject_Del(self); +} + +static PyTypeObject xu_message_type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "message", + sizeof(xu_message_object), + 0, + xu_message_dealloc, /* tp_dealloc */ + NULL, /* tp_print */ + xu_message_getattr, /* tp_getattr */ + NULL, /* tp_setattr */ + NULL, /* tp_compare */ + NULL, /* tp_repr */ + NULL, /* tp_as_number */ + NULL, /* tp_as_sequence */ + NULL, /* tp_as_mapping */ + NULL /* tp_hash */ +}; + + + +/* + * *********************** PORT *********************** + */ + +static control_if_t *map_control_interface(int fd, unsigned long pfn) +{ + char *vaddr = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE, + MAP_SHARED, fd, pfn * PAGE_SIZE); + if ( vaddr == MAP_FAILED ) + return NULL; + return (control_if_t *)(vaddr + 2048); +} +static void unmap_control_interface(int fd, control_if_t *c) +{ + char *vaddr = (char *)c - 2048; + (void)munmap(vaddr, PAGE_SIZE); +} + +typedef struct xu_port_object { + PyObject_HEAD; + int mem_fd; + int xc_handle; + u32 remote_dom; + int local_port, remote_port; + control_if_t *interface; + CONTROL_RING_IDX tx_req_cons, tx_resp_prod; + CONTROL_RING_IDX rx_req_prod, rx_resp_cons; +} xu_port_object; + +static PyObject *port_error; + +static int xup_connect(xu_port_object *xup, domid_t dom, + int local_port, int remote_port){ + // From our prespective rx = producer, tx = consumer. + int err = 0; + printf("%s> dom=%u %d:%d\n", __FUNCTION__, (unsigned int)dom, + local_port, remote_port); + + // Consumer = tx. + //xup->interface->tx_resp_prod = 0; + //xup->interface->tx_req_prod = 0; + xup->tx_resp_prod = xup->interface->tx_resp_prod; + xup->tx_req_cons = xup->interface->tx_resp_prod; + printf("%s> tx: %u %u : %u %u\n", __FUNCTION__, + (unsigned int)xup->interface->tx_resp_prod, + (unsigned int)xup->tx_resp_prod, + (unsigned int)xup->tx_req_cons, + (unsigned int)xup->interface->tx_req_prod); + + // Producer = rx. + //xup->interface->rx_req_prod = 0; + //xup->interface->rx_resp_prod = 0; + xup->rx_req_prod = xup->interface->rx_req_prod; + xup->rx_resp_cons = xup->interface->rx_resp_prod; + printf("%s> rx: %u %u : %u %u\n", __FUNCTION__, + (unsigned int)xup->rx_resp_cons, + (unsigned int)xup->interface->rx_resp_prod, + (unsigned int)xup->interface->rx_req_prod, + (unsigned int)xup->rx_req_prod); + + xup->remote_dom = dom; + xup->local_port = local_port; + xup->remote_port = remote_port; + + printf("%s< err=%d\n", __FUNCTION__, err); + return err; +} + +static PyObject *xu_port_notify(PyObject *self, PyObject *args) +{ + xu_port_object *xup = (xu_port_object *)self; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + (void)xc_evtchn_send(xup->xc_handle, xup->local_port); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject *xu_port_read_request(PyObject *self, PyObject *args) +{ + xu_port_object *xup = (xu_port_object *)self; + xu_message_object *xum; + CONTROL_RING_IDX c = xup->tx_req_cons; + control_if_t *cif = xup->interface; + control_msg_t *cmsg; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + if ( (c == cif->tx_req_prod) || + ((c - xup->tx_resp_prod) == CONTROL_RING_SIZE) ) + { + PyErr_SetString(port_error, "no request to read"); + return NULL; + } + + cmsg = &cif->tx_ring[MASK_CONTROL_IDX(c)]; + xum = PyObject_New(xu_message_object, &xu_message_type); + memcpy(&xum->msg, cmsg, sizeof(*cmsg)); + if ( xum->msg.length > sizeof(xum->msg.msg) ) + xum->msg.length = sizeof(xum->msg.msg); + xup->tx_req_cons++; + return (PyObject *)xum; +} + +static PyObject *xu_port_write_request(PyObject *self, PyObject *args) +{ + xu_port_object *xup = (xu_port_object *)self; + xu_message_object *xum; + CONTROL_RING_IDX p = xup->rx_req_prod; + control_if_t *cif = xup->interface; + control_msg_t *cmsg; + + if ( !PyArg_ParseTuple(args, "O", (PyObject **)&xum) ) + return NULL; + + if ( !PyObject_TypeCheck((PyObject *)xum, &xu_message_type) ) + { + PyErr_SetString(PyExc_TypeError, "expected a " XENPKG ".message"); + return NULL; + } + + if ( ((p - xup->rx_resp_cons) == CONTROL_RING_SIZE) ) + { + PyErr_SetString(port_error, "no space to write request"); + return NULL; + } + + cmsg = &cif->rx_ring[MASK_CONTROL_IDX(p)]; + memcpy(cmsg, &xum->msg, sizeof(*cmsg)); + + xup->rx_req_prod = cif->rx_req_prod = p + 1; + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject *xu_port_read_response(PyObject *self, PyObject *args) +{ + xu_port_object *xup = (xu_port_object *)self; + xu_message_object *xum; + CONTROL_RING_IDX c = xup->rx_resp_cons; + control_if_t *cif = xup->interface; + control_msg_t *cmsg; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + if ( (c == cif->rx_resp_prod) || (c == xup->rx_req_prod) ) + { + PyErr_SetString(port_error, "no response to read"); + return NULL; + } + + cmsg = &cif->rx_ring[MASK_CONTROL_IDX(c)]; + xum = PyObject_New(xu_message_object, &xu_message_type); + memcpy(&xum->msg, cmsg, sizeof(*cmsg)); + if ( xum->msg.length > sizeof(xum->msg.msg) ) + xum->msg.length = sizeof(xum->msg.msg); + xup->rx_resp_cons++; + return (PyObject *)xum; +} + +static PyObject *xu_port_write_response(PyObject *self, PyObject *args) +{ + xu_port_object *xup = (xu_port_object *)self; + xu_message_object *xum; + CONTROL_RING_IDX p = xup->tx_resp_prod; + control_if_t *cif = xup->interface; + control_msg_t *cmsg; + + if ( !PyArg_ParseTuple(args, "O", (PyObject **)&xum) ) + return NULL; + + if ( !PyObject_TypeCheck((PyObject *)xum, &xu_message_type) ) + { + PyErr_SetString(PyExc_TypeError, "expected a " XENPKG ".message"); + return NULL; + } + + if ( p == xup->tx_req_cons ) + { + PyErr_SetString(port_error, "no space to write response"); + return NULL; + } + + cmsg = &cif->tx_ring[MASK_CONTROL_IDX(p)]; + memcpy(cmsg, &xum->msg, sizeof(*cmsg)); + + xup->tx_resp_prod = cif->tx_resp_prod = p + 1; + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject *xu_port_request_to_read(PyObject *self, PyObject *args) +{ + xu_port_object *xup = (xu_port_object *)self; + CONTROL_RING_IDX c = xup->tx_req_cons; + control_if_t *cif = xup->interface; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + if ( (c == cif->tx_req_prod) || + ((c - xup->tx_resp_prod) == CONTROL_RING_SIZE) ) + return PyInt_FromLong(0); + + return PyInt_FromLong(1); +} + +static PyObject *xu_port_space_to_write_request(PyObject *self, PyObject *args) +{ + xu_port_object *xup = (xu_port_object *)self; + CONTROL_RING_IDX p = xup->rx_req_prod; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + if ( ((p - xup->rx_resp_cons) == CONTROL_RING_SIZE) ) + return PyInt_FromLong(0); + + return PyInt_FromLong(1); +} + +static PyObject *xu_port_response_to_read(PyObject *self, PyObject *args) +{ + xu_port_object *xup = (xu_port_object *)self; + CONTROL_RING_IDX c = xup->rx_resp_cons; + control_if_t *cif = xup->interface; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + if ( (c == cif->rx_resp_prod) || (c == xup->rx_req_prod) ) + return PyInt_FromLong(0); + + return PyInt_FromLong(1); +} + +static PyObject *xu_port_space_to_write_response( + PyObject *self, PyObject *args) +{ + xu_port_object *xup = (xu_port_object *)self; + CONTROL_RING_IDX p = xup->tx_resp_prod; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + if ( p == xup->tx_req_cons ) + return PyInt_FromLong(0); + + return PyInt_FromLong(1); +} + +static PyMethodDef xu_port_methods[] = { + { "notify", + (PyCFunction)xu_port_notify, + METH_VARARGS, + "Send a notification to the remote end.\n" }, + + { "read_request", + (PyCFunction)xu_port_read_request, + METH_VARARGS, + "Read a request message from the control interface.\n" }, + + { "write_request", + (PyCFunction)xu_port_write_request, + METH_VARARGS, + "Write a request message to the control interface.\n" }, + + { "read_response", + (PyCFunction)xu_port_read_response, + METH_VARARGS, + "Read a response message from the control interface.\n" }, + + { "write_response", + (PyCFunction)xu_port_write_response, + METH_VARARGS, + "Write a response message to the control interface.\n" }, + + { "request_to_read", + (PyCFunction)xu_port_request_to_read, + METH_VARARGS, + "Returns TRUE if there is a request message to read.\n" }, + + { "space_to_write_request", + (PyCFunction)xu_port_space_to_write_request, + METH_VARARGS, + "Returns TRUE if there is space to write a request message.\n" }, + + { "response_to_read", + (PyCFunction)xu_port_response_to_read, + METH_VARARGS, + "Returns TRUE if there is a response message to read.\n" }, + + { "space_to_write_response", + (PyCFunction)xu_port_space_to_write_response, + METH_VARARGS, + "Returns TRUE if there is space to write a response message.\n" }, + + { NULL, NULL, 0, NULL } +}; + +staticforward PyTypeObject xu_port_type; + +static PyObject *xu_port_new(PyObject *self, PyObject *args) +{ + xu_port_object *xup; + u32 dom; + int port1, port2; + xc_dominfo_t info; + + if ( !PyArg_ParseTuple(args, "i", &dom) ) + return NULL; + + xup = PyObject_New(xu_port_object, &xu_port_type); + + if ( (xup->mem_fd = open("/dev/mem", O_RDWR)) == -1 ) + { + PyErr_SetString(port_error, "Could not open '/dev/mem'"); + goto fail1; + } + + /* Set the General-Purpose Subject whose page frame will be mapped. */ + (void)ioctl(xup->mem_fd, _IO('M', 1), (unsigned long)dom); + + if ( (xup->xc_handle = xc_interface_open()) == -1 ) + { + PyErr_SetString(port_error, "Could not open Xen control interface"); + goto fail2; + } + + if ( dom == 0 ) + { + /* + * The control-interface event channel for DOM0 is already set up. + * We use an ioctl to discover the port at our end of the channel. + */ + port1 = ioctl(xup->xc_handle, IOCTL_PRIVCMD_INITDOMAIN_EVTCHN, NULL); + port2 = -1; /* We don't need the remote end of the DOM0 link. */ + if ( port1 < 0 ) + { + PyErr_SetString(port_error, "Could not open channel to DOM0"); + goto fail3; + } + } + else if ( xc_evtchn_bind_interdomain(xup->xc_handle, + DOMID_SELF, dom, + &port1, &port2) != 0 ) + { + PyErr_SetString(port_error, "Could not open channel to domain"); + goto fail3; + } + + if ( (xc_domain_getinfo(xup->xc_handle, dom, 1, &info) != 1) || + (info.domid != dom) ) + { + PyErr_SetString(port_error, "Failed to obtain domain status"); + goto fail4; + } + + xup->interface = + map_control_interface(xup->mem_fd, info.shared_info_frame); + if ( xup->interface == NULL ) + { + PyErr_SetString(port_error, "Failed to map domain control interface"); + goto fail4; + } + + xup_connect(xup, dom, port1, port2); + return (PyObject *)xup; + + + fail4: + (void)xc_evtchn_close(xup->xc_handle, DOMID_SELF, port1); + fail3: + (void)xc_interface_close(xup->xc_handle); + fail2: + (void)close(xup->mem_fd); + fail1: + PyObject_Del((PyObject *)xup); + return NULL; +} + +static PyObject *xu_port_getattr(PyObject *obj, char *name) +{ + xu_port_object *xup = (xu_port_object *)obj; + if ( strcmp(name, "local_port") == 0 ) + return PyInt_FromLong(xup->local_port); + if ( strcmp(name, "remote_port") == 0 ) + return PyInt_FromLong(xup->remote_port); + if ( strcmp(name, "remote_dom") == 0 ) + return PyInt_FromLong(xup->remote_dom); + return Py_FindMethod(xu_port_methods, obj, name); +} + +static void xu_port_dealloc(PyObject *self) +{ + xu_port_object *xup = (xu_port_object *)self; + unmap_control_interface(xup->mem_fd, xup->interface); + if ( xup->remote_dom != 0 ) + (void)xc_evtchn_close(xup->xc_handle, DOMID_SELF, xup->local_port); + (void)xc_interface_close(xup->xc_handle); + (void)close(xup->mem_fd); + PyObject_Del(self); +} + +static PyTypeObject xu_port_type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "port", + sizeof(xu_port_object), + 0, + xu_port_dealloc, /* tp_dealloc */ + NULL, /* tp_print */ + xu_port_getattr, /* tp_getattr */ + NULL, /* tp_setattr */ + NULL, /* tp_compare */ + NULL, /* tp_repr */ + NULL, /* tp_as_number */ + NULL, /* tp_as_sequence */ + NULL, /* tp_as_mapping */ + NULL /* tp_hash */ +}; + + + +/* + * *********************** BUFFER *********************** + */ + +#define BUFSZ 65536 +#define MASK_BUF_IDX(_i) ((_i)&(BUFSZ-1)) +typedef unsigned int BUF_IDX; + +typedef struct { + PyObject_HEAD; + char *buf; + unsigned int prod, cons; +} xu_buffer_object; + +static PyObject *__xu_buffer_peek(xu_buffer_object *xub, int max) +{ + PyObject *str1, *str2; + int len1, len2, c = MASK_BUF_IDX(xub->cons); + + len1 = xub->prod - xub->cons; + if ( len1 > (BUFSZ - c) ) /* clip to ring wrap */ + len1 = BUFSZ - c; + if ( len1 > max ) /* clip to specified maximum */ + len1 = max; + if ( len1 < 0 ) /* sanity */ + len1 = 0; + + if ( (str1 = PyString_FromStringAndSize(&xub->buf[c], len1)) == NULL ) + return NULL; + + if ( (len1 < (xub->prod - xub->cons)) && (len1 < max) ) + { + len2 = max - len1; + if ( len2 > MASK_BUF_IDX(xub->prod) ) + len2 = MASK_BUF_IDX(xub->prod); + if ( len2 > 0 ) + { + str2 = PyString_FromStringAndSize(&xub->buf[0], len2); + if ( str2 == NULL ) + return NULL; + PyString_ConcatAndDel(&str1, str2); + if ( str1 == NULL ) + return NULL; + } + } + + return str1; +} + +static PyObject *xu_buffer_peek(PyObject *self, PyObject *args) +{ + xu_buffer_object *xub = (xu_buffer_object *)self; + int max = 1024; + + if ( !PyArg_ParseTuple(args, "|i", &max) ) + return NULL; + + return __xu_buffer_peek(xub, max); +} + +static PyObject *xu_buffer_read(PyObject *self, PyObject *args) +{ + xu_buffer_object *xub = (xu_buffer_object *)self; + PyObject *str; + int max = 1024; + + if ( !PyArg_ParseTuple(args, "|i", &max) ) + return NULL; + + if ( (str = __xu_buffer_peek(xub, max)) != NULL ) + xub->cons += PyString_Size(str); + + return str; +} + +static PyObject *xu_buffer_discard(PyObject *self, PyObject *args) +{ + xu_buffer_object *xub = (xu_buffer_object *)self; + int max, len; + + if ( !PyArg_ParseTuple(args, "i", &max) ) + return NULL; + + len = xub->prod - xub->cons; + if ( len > max ) + len = max; + if ( len < 0 ) + len = 0; + + xub->cons += len; + + return PyInt_FromLong(len); +} + +static PyObject *xu_buffer_write(PyObject *self, PyObject *args) +{ + xu_buffer_object *xub = (xu_buffer_object *)self; + char *str; + int len, len1, len2; + + if ( !PyArg_ParseTuple(args, "s#", &str, &len) ) + return NULL; + + len1 = len; + if ( len1 > (BUFSZ - MASK_BUF_IDX(xub->prod)) ) + len1 = BUFSZ - MASK_BUF_IDX(xub->prod); + if ( len1 > (BUFSZ - (xub->prod - xub->cons)) ) + len1 = BUFSZ - (xub->prod - xub->cons); + + if ( len1 == 0 ) + return PyInt_FromLong(0); + + memcpy(&xub->buf[MASK_BUF_IDX(xub->prod)], &str[0], len1); + xub->prod += len1; + + if ( len1 < len ) + { + len2 = len - len1; + if ( len2 > (BUFSZ - MASK_BUF_IDX(xub->prod)) ) + len2 = BUFSZ - MASK_BUF_IDX(xub->prod); + if ( len2 > (BUFSZ - (xub->prod - xub->cons)) ) + len2 = BUFSZ - (xub->prod - xub->cons); + if ( len2 != 0 ) + { + memcpy(&xub->buf[MASK_BUF_IDX(xub->prod)], &str[len1], len2); + xub->prod += len2; + return PyInt_FromLong(len1 + len2); + } + } + + return PyInt_FromLong(len1); +} + +static PyObject *xu_buffer_empty(PyObject *self, PyObject *args) +{ + xu_buffer_object *xub = (xu_buffer_object *)self; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + if ( xub->cons == xub->prod ) + return PyInt_FromLong(1); + + return PyInt_FromLong(0); +} + +static PyObject *xu_buffer_full(PyObject *self, PyObject *args) +{ + xu_buffer_object *xub = (xu_buffer_object *)self; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + if ( (xub->prod - xub->cons) == BUFSZ ) + return PyInt_FromLong(1); + + return PyInt_FromLong(0); +} + +static PyMethodDef xu_buffer_methods[] = { + { "peek", + (PyCFunction)xu_buffer_peek, + METH_VARARGS, + "Peek up to @max bytes from the buffer. Returns a string.\n" }, + + { "read", + (PyCFunction)xu_buffer_read, + METH_VARARGS, + "Read up to @max bytes from the buffer. Returns a string.\n" }, + + { "discard", + (PyCFunction)xu_buffer_discard, + METH_VARARGS, + "Discard up to @max bytes from the buffer. Returns number of bytes.\n" }, + + { "write", + (PyCFunction)xu_buffer_write, + METH_VARARGS, + "Write @string into buffer. Return number of bytes written.\n" }, + + { "empty", + (PyCFunction)xu_buffer_empty, + METH_VARARGS, + "Return TRUE if the buffer is empty.\n" }, + + { "full", + (PyCFunction)xu_buffer_full, + METH_VARARGS, + "Return TRUE if the buffer is full.\n" }, + + { NULL, NULL, 0, NULL } +}; + +staticforward PyTypeObject xu_buffer_type; + +static PyObject *xu_buffer_new(PyObject *self, PyObject *args) +{ + xu_buffer_object *xub; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + xub = PyObject_New(xu_buffer_object, &xu_buffer_type); + + if ( (xub->buf = malloc(BUFSZ)) == NULL ) + { + PyObject_Del((PyObject *)xub); + return NULL; + } + + xub->prod = xub->cons = 0; + + return (PyObject *)xub; +} + +static PyObject *xu_buffer_getattr(PyObject *obj, char *name) +{ + return Py_FindMethod(xu_buffer_methods, obj, name); +} + +static void xu_buffer_dealloc(PyObject *self) +{ + xu_buffer_object *xub = (xu_buffer_object *)self; + free(xub->buf); + PyObject_Del(self); +} + +static PyTypeObject xu_buffer_type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "buffer", + sizeof(xu_buffer_object), + 0, + xu_buffer_dealloc, /* tp_dealloc */ + NULL, /* tp_print */ + xu_buffer_getattr, /* tp_getattr */ + NULL, /* tp_setattr */ + NULL, /* tp_compare */ + NULL, /* tp_repr */ + NULL, /* tp_as_number */ + NULL, /* tp_as_sequence */ + NULL, /* tp_as_mapping */ + NULL /* tp_hash */ +}; + + + +/* + * *********************** MODULE WRAPPER *********************** + */ + +static void handle_child_death(int dummy) +{ + while ( waitpid(-1, NULL, WNOHANG) > 0 ) + continue; +} + +static PyObject *xu_autoreap(PyObject *self, PyObject *args) +{ + struct sigaction sa; + + if ( !PyArg_ParseTuple(args, "") ) + return NULL; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = handle_child_death; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_NOCLDSTOP | SA_RESTART; + (void)sigaction(SIGCHLD, &sa, NULL); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef xu_methods[] = { + { "notifier", xu_notifier_new, METH_VARARGS, + "Create a new notifier." }, + { "message", xu_message_new, METH_VARARGS, + "Create a new communications message." }, + { "port", xu_port_new, METH_VARARGS, + "Create a new communications port." }, + { "buffer", xu_buffer_new, METH_VARARGS, + "Create a new ring buffer." }, + { "autoreap", xu_autoreap, METH_VARARGS, + "Ensure that zombie children are automatically reaped by the OS." }, + { NULL, NULL, 0, NULL } +}; + +PyMODINIT_FUNC initxu(void) +{ + PyObject *m, *d; + + m = Py_InitModule(XENPKG, xu_methods); + + d = PyModule_GetDict(m); + port_error = PyErr_NewException(XENPKG ".PortError", NULL, NULL); + PyDict_SetItemString(d, "PortError", port_error); +} diff --git a/tools/python/xen/util/Brctl.py b/tools/python/xen/util/Brctl.py new file mode 100644 index 0000000000..9d3eba1e5f --- /dev/null +++ b/tools/python/xen/util/Brctl.py @@ -0,0 +1,160 @@ +"""Bridge control utilities. +""" +import os +import os.path +import re +import sys + +os.defpath = os.defpath + ':/sbin:/usr/sbin:/usr/local/sbin' +CMD_IFCONFIG = 'ifconfig' +CMD_ROUTE = 'route' +CMD_BRCTL = 'brctl' +CMD_IPTABLES = "iptables" + +opts = None + +class Opts: + + def __init__(self, defaults): + for (k, v) in defaults.items(): + setattr(self, k, v) + pass + +def cmd(p, s): + """Print and execute command 'p' with args 's'. + """ + global opts + c = p + ' ' + s + if opts.verbose: print c + if not opts.dryrun: + os.system(c) + +def vif_bridge_add(params): + """Add the network interface for vif on dom to a bridge. + """ + cmd(CMD_BRCTL, 'addif %(bridge)s %(vif)s' % params) + +def vif_bridge_rem(params): + """Remove the network interface for vif on dom from a bridge. + """ + cmd(CMD_BRCTL, 'delif %(bridge)s %(vif)s' % params) + +def vif_restrict_addr(vif, addr, delete=0): + d = { 'vif': vif, 'addr': addr} + if delete: + d['flag'] = '-D' + else: + d['flag'] = '-A' + cmd(CMD_IPTABLES, '-P FORWARD DROP') + cmd(CMD_IPTABLES, '%(flag)s FORWARD -m physdev --physdev-in %(vif)s -s %(addr)s -j ACCEPT' % d) + cmd(CMD_IPTABLES, '%(flag)s FORWARD -m physdev --physdev-out %(vif)s -d %(addr)s -j ACCEPT' % d) + +def bridge_create(bridge, **kwd): + """Create a bridge. + Defaults hello time to 0, forward delay to 0 and stp off. + """ + cmd(CMD_BRCTL, 'addbr %s' % bridge) + if kwd.get('hello', None) is None: + kwd['hello'] = 0 + if kwd.get('fd', None) is None: + kwd['fd'] = 0 + if kwd.get('stp', None) is None: + kwd['stp'] = 'off' + bridge_set(bridge, **kwd) + +def bridge_set(bridge, hello=None, fd=None, stp=None): + """Set bridge parameters. + """ + if hello is not None: + cmd(CMD_BRCTL, 'sethello %s %d' % (bridge, hello)) + if fd is not None: + cmd(CMD_BRCTL, 'setfd %s %d' % (bridge, fd)) + if stp is not None: + cmd(CMD_BRCTL, 'stp %s %s' % (bridge, stp)) + +def bridge_del(bridge): + """Delete a bridge. + """ + cmd(CMD_BRCTL, 'delbr %s' % bridge) + +def routes(): + """Return a list of the routes. + """ + fin = os.popen(CMD_ROUTE + ' -n', 'r') + routes = [] + for x in fin: + if x.startswith('Kernel'): continue + if x.startswith('Destination'): continue + x = x.strip() + y = x.split() + z = { 'destination': y[0], + 'gateway' : y[1], + 'mask' : y[2], + 'flags' : y[3], + 'metric' : y[4], + 'ref' : y[5], + 'use' : y[6], + 'interface' : y[7] } + routes.append(z) + return routes + +def ifconfig(interface): + """Return the ip config for an interface, + """ + fin = os.popen(CMD_IFCONFIG + ' %s' % interface, 'r') + inetre = re.compile('\s*inet\s*addr:(?P
\S*)\s*Bcast:(?P\S*)\s*Mask:(?P\S*)') + info = None + for x in fin: + m = inetre.match(x) + if not m: continue + info = m.groupdict() + info['interface'] = interface + break + return info + +def reconfigure(interface, bridge): + """Reconfigure an interface to be attached to a bridge, and give the bridge + the IP address etc. from interface. Move the default route to the interface + to the bridge. + + """ + global opts + intf_info = ifconfig(interface) + if not intf_info: + print >>sys.stderr, 'Interface not found:', interface + return + #bridge_info = ifconfig(bridge) + #if not bridge_info: + # print >>sys.stderr, 'Bridge not found:', bridge + # return + route_info = routes() + intf_info['bridge'] = bridge + intf_info['gateway'] = None + for r in route_info: + if (r['destination'] == '0.0.0.0' and + 'G' in r['flags'] and + r['interface'] == interface): + intf_info['gateway'] = r['gateway'] + if not intf_info['gateway']: + print >>sys.stderr, 'Gateway not found: ', interface + return + cmd(CMD_IFCONFIG, + '%(bridge)s %(address)s netmask %(mask)s broadcast %(broadcast)s up' + % intf_info) + cmd(CMD_ROUTE, + 'add default gateway %(gateway)s dev %(bridge)s' + % intf_info) + cmd(CMD_BRCTL, 'addif %(bridge)s %(interface)s' % intf_info) + cmd(CMD_IFCONFIG, '%(interface)s 0.0.0.0' % intf_info) + +defaults = { + 'verbose' : 1, + 'dryrun' : 0, + } + +opts = Opts(defaults) + +def set_opts(val): + global opts + opts = val + return opts diff --git a/tools/python/xen/util/__init__.py b/tools/python/xen/util/__init__.py new file mode 100644 index 0000000000..8d1c8b69c3 --- /dev/null +++ b/tools/python/xen/util/__init__.py @@ -0,0 +1 @@ + diff --git a/tools/python/xen/util/console_client.py b/tools/python/xen/util/console_client.py new file mode 100644 index 0000000000..7ac63aeb75 --- /dev/null +++ b/tools/python/xen/util/console_client.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python + +############################################## +# Console client for Xen guest OSes +# Copyright (c) 2004, K A Fraser +############################################## + +import errno, os, signal, socket, struct, sys + +from termios import * +# Indexes into termios.tcgetattr() list. +IFLAG = 0 +OFLAG = 1 +CFLAG = 2 +LFLAG = 3 +ISPEED = 4 +OSPEED = 5 +CC = 6 + +def __child_death(signum, frame): + global stop + stop = True + +def __recv_from_sock(sock): + global stop + stop = False + while not stop: + try: + data = sock.recv(1024) + os.write(1, data) + except socket.error, error: + if error[0] != errno.EINTR: + raise + os.wait() + +def __send_to_sock(sock): + while 1: + data = os.read(0,1024) + if ord(data[0]) == ord(']')-64: + break + try: + sock.send(data) + except socket.error, error: + if error[0] == errno.EPIPE: + sys.exit(0) + if error[0] != errno.EINTR: + raise + sys.exit(0) + +def connect(host,port): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) + sock.connect((host,port)) + + oattrs = tcgetattr(0) + nattrs = tcgetattr(0) + nattrs[IFLAG] = nattrs[IFLAG] & ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON) + nattrs[OFLAG] = nattrs[OFLAG] & ~(OPOST) + nattrs[CFLAG] = nattrs[CFLAG] & ~(CSIZE | PARENB) + nattrs[CFLAG] = nattrs[CFLAG] | CS8 + nattrs[LFLAG] = nattrs[LFLAG] & ~(ECHO | ICANON | IEXTEN | ISIG) + nattrs[CC][VMIN] = 1 + nattrs[CC][VTIME] = 0 + + if os.fork(): + signal.signal(signal.SIGCHLD, __child_death) + print "************ REMOTE CONSOLE: CTRL-] TO QUIT ********" + tcsetattr(0, TCSAFLUSH, nattrs) + try: + __recv_from_sock(sock) + finally: + tcsetattr(0, TCSAFLUSH, oattrs) + print + print "************ REMOTE CONSOLE EXITED *****************" + else: + signal.signal(signal.SIGPIPE, signal.SIG_IGN) + __send_to_sock(sock) + +if __name__ == '__main__': + if len(sys.argv) != 3: + print sys.argv[0] + " " + sys.exit(1) + connect(str(sys.argv[1]),int(sys.argv[2])) diff --git a/tools/python/xen/util/ip.py b/tools/python/xen/util/ip.py new file mode 100644 index 0000000000..8396e0d014 --- /dev/null +++ b/tools/python/xen/util/ip.py @@ -0,0 +1,113 @@ +import os +import re +import socket +import struct + +def readlines(fd): + """Version of readlines safe against EINTR. + """ + import errno + + lines = [] + while 1: + try: + line = fd.readline() + except IOError, ex: + if ex.errno == errno.EINTR: + continue + else: + raise + if line == '': break + lines.append(line) + return lines + +def readline(fd): + """Version of readline safe against EINTR. + """ + while 1: + try: + return fd.readline() + except IOError, ex: + if ex.errno == errno.EINTR: + continue + else: + raise + +##### Networking-related functions + +"""Bridge for network backend. +When bridging is used, eth0 may not have an IP address, +as it may have been moved onto the bridge. +""" +NBE_BRIDGE = 'nbe-br' + +def get_current_ipaddr(dev='eth0'): + """Return a string containing the primary IP address for the given + network interface (default 'eth0'). + """ + fd = os.popen( '/sbin/ifconfig ' + dev + ' 2>/dev/null' ) + lines = readlines(fd) + for line in lines: + m = re.search( '^\s+inet addr:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*', + line ) + if m: + return m.group(1) + if dev == 'eth0': + return get_current_ipaddr(NBE_BRIDGE) + return None + +def get_current_ipmask(dev='eth0'): + """Return a string containing the primary IP netmask for the given + network interface (default 'eth0'). + """ + fd = os.popen( '/sbin/ifconfig ' + dev + ' 2>/dev/null' ) + lines = readlines(fd) + for line in lines: + m = re.search( '^.+Mask:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*', + line ) + if m: + return m.group(1) + if dev == 'eth0': + return get_current_ipmask(NBE_BRIDGE) + return None + +def get_current_ipgw(dev='eth0'): + """Return a string containing the IP gateway for the given + network interface (default 'eth0'). + """ + fd = os.popen( '/sbin/route -n' ) + lines = readlines(fd) + for line in lines: + m = re.search( '^\S+\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)' + + '\s+\S+\s+\S*G.*' + dev + '.*', line ) + if m: + return m.group(1) + if dev == 'eth0': + return get_current_ipgw(NBE_BRIDGE) + return None + +def inet_aton(addr): + """Convert an IP addr in IPv4 dot notation into an int. + """ + b = socket.inet_aton(addr) + return struct.unpack('!I', b)[0] + +def inet_ntoa(n): + """Convert an int into an IP addr in IPv4 dot notation. + """ + b = struct.pack('!I', n) + return socket.inet_ntoa(b) + +def add_offset_to_ip(addr, offset): + """Add a numerical offset to an IP addr in IPv4 dot notation. + """ + n = inet_aton(addr) + n += offset + return inet_ntoa(n) + +def check_subnet( ip, network, netmask ): + n_ip = inet_aton(ip) + n_net = inet_aton(network) + n_mask = inet_aton(netmask) + return (n_ip & n_mask) == (n_net & n_mask) + diff --git a/tools/python/xen/util/tempfile.py b/tools/python/xen/util/tempfile.py new file mode 100644 index 0000000000..756d8c8727 --- /dev/null +++ b/tools/python/xen/util/tempfile.py @@ -0,0 +1,451 @@ +"""Temporary files. + +This module provides generic, low- and high-level interfaces for +creating temporary files and directories. The interfaces listed +as "safe" just below can be used without fear of race conditions. +Those listed as "unsafe" cannot, and are provided for backward +compatibility only. + +This module also provides some data items to the user: + + TMP_MAX - maximum number of names that will be tried before + giving up. + template - the default prefix for all temporary names. + You may change this to control the default prefix. + tempdir - If this is set to a string before the first use of + any routine from this module, it will be considered as + another candidate location to store temporary files. +""" + +__all__ = [ + "NamedTemporaryFile", "TemporaryFile", # high level safe interfaces + "mkstemp", "mkdtemp", # low level safe interfaces + "mktemp", # deprecated unsafe interface + "TMP_MAX", "gettempprefix", # constants + "tempdir", "gettempdir" + ] + + +# Imports. + +import os as _os +import errno as _errno +from random import Random as _Random + +if _os.name == 'mac': + import Carbon.Folder as _Folder + import Carbon.Folders as _Folders + +try: + import fcntl as _fcntl + # If PYTHONCASEOK is set on Windows, stinking FCNTL.py gets + # imported, and we don't get an ImportError then. Provoke + # an AttributeError instead in that case. + _fcntl.fcntl +except (ImportError, AttributeError): + def _set_cloexec(fd): + pass +else: + def _set_cloexec(fd): + flags = _fcntl.fcntl(fd, _fcntl.F_GETFD, 0) + if flags >= 0: + # flags read successfully, modify + flags |= _fcntl.FD_CLOEXEC + _fcntl.fcntl(fd, _fcntl.F_SETFD, flags) + + +try: + import thread as _thread +except ImportError: + import dummy_thread as _thread +_allocate_lock = _thread.allocate_lock + +_text_openflags = _os.O_RDWR | _os.O_CREAT | _os.O_EXCL +if hasattr(_os, 'O_NOINHERIT'): + _text_openflags |= _os.O_NOINHERIT +if hasattr(_os, 'O_NOFOLLOW'): + _text_openflags |= _os.O_NOFOLLOW + +_bin_openflags = _text_openflags +if hasattr(_os, 'O_BINARY'): + _bin_openflags |= _os.O_BINARY + +if hasattr(_os, 'TMP_MAX'): + TMP_MAX = _os.TMP_MAX +else: + TMP_MAX = 10000 + +template = "tmp" + +tempdir = None + +# Internal routines. + +_once_lock = _allocate_lock() + +class _RandomNameSequence: + """An instance of _RandomNameSequence generates an endless + sequence of unpredictable strings which can safely be incorporated + into file names. Each string is six characters long. Multiple + threads can safely use the same instance at the same time. + + _RandomNameSequence is an iterator.""" + + characters = ("abcdefghijklmnopqrstuvwxyz" + + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + + "0123456789-_") + + def __init__(self): + self.mutex = _allocate_lock() + self.rng = _Random() + self.normcase = _os.path.normcase + + def __iter__(self): + return self + + def next(self): + m = self.mutex + c = self.characters + choose = self.rng.choice + + m.acquire() + try: + letters = [choose(c) for dummy in "123456"] + finally: + m.release() + + return self.normcase(''.join(letters)) + +def _candidate_tempdir_list(): + """Generate a list of candidate temporary directories which + _get_default_tempdir will try.""" + + dirlist = [] + + # First, try the environment. + for envname in 'TMPDIR', 'TEMP', 'TMP': + dirname = _os.getenv(envname) + if dirname: dirlist.append(dirname) + + # Failing that, try OS-specific locations. + if _os.name == 'mac': + try: + fsr = _Folder.FSFindFolder(_Folders.kOnSystemDisk, + _Folders.kTemporaryFolderType, 1) + dirname = fsr.as_pathname() + dirlist.append(dirname) + except _Folder.error: + pass + elif _os.name == 'riscos': + dirname = _os.getenv('Wimp$ScrapDir') + if dirname: dirlist.append(dirname) + elif _os.name == 'nt': + dirlist.extend([ r'c:\temp', r'c:\tmp', r'\temp', r'\tmp' ]) + else: + dirlist.extend([ '/tmp', '/var/tmp', '/usr/tmp' ]) + + # As a last resort, the current directory. + try: + dirlist.append(_os.getcwd()) + except (AttributeError, _os.error): + dirlist.append(_os.curdir) + + return dirlist + +def _get_default_tempdir(): + """Calculate the default directory to use for temporary files. + This routine should be called exactly once. + + We determine whether or not a candidate temp dir is usable by + trying to create and write to a file in that directory. If this + is successful, the test file is deleted. To prevent denial of + service, the name of the test file must be randomized.""" + + namer = _RandomNameSequence() + dirlist = _candidate_tempdir_list() + flags = _text_openflags + + for dir in dirlist: + if dir != _os.curdir: + dir = _os.path.normcase(_os.path.abspath(dir)) + # Try only a few names per directory. + for seq in xrange(100): + name = namer.next() + filename = _os.path.join(dir, name) + try: + fd = _os.open(filename, flags, 0600) + fp = _os.fdopen(fd, 'w') + fp.write('blat') + fp.close() + _os.unlink(filename) + del fp, fd + return dir + except (OSError, IOError), e: + if e[0] != _errno.EEXIST: + break # no point trying more names in this directory + pass + raise IOError, (_errno.ENOENT, + ("No usable temporary directory found in %s" % dirlist)) + +_name_sequence = None + +def _get_candidate_names(): + """Common setup sequence for all user-callable interfaces.""" + + global _name_sequence + if _name_sequence is None: + _once_lock.acquire() + try: + if _name_sequence is None: + _name_sequence = _RandomNameSequence() + finally: + _once_lock.release() + return _name_sequence + + +def _mkstemp_inner(dir, pre, suf, flags): + """Code common to mkstemp, TemporaryFile, and NamedTemporaryFile.""" + + names = _get_candidate_names() + + for seq in xrange(TMP_MAX): + name = names.next() + file = _os.path.join(dir, pre + name + suf) + try: + fd = _os.open(file, flags, 0600) + _set_cloexec(fd) + return (fd, file) + except OSError, e: + if e.errno == _errno.EEXIST: + continue # try again + raise + + raise IOError, (_errno.EEXIST, "No usable temporary file name found") + + +# User visible interfaces. + +def gettempprefix(): + """Accessor for tempdir.template.""" + return template + +tempdir = None + +def gettempdir(): + """Accessor for tempdir.tempdir.""" + global tempdir + if tempdir is None: + _once_lock.acquire() + try: + if tempdir is None: + tempdir = _get_default_tempdir() + finally: + _once_lock.release() + return tempdir + +def mkstemp(suffix="", prefix=template, dir=None, text=False): + """mkstemp([suffix, [prefix, [dir, [text]]]]) + User-callable function to create and return a unique temporary + file. The return value is a pair (fd, name) where fd is the + file descriptor returned by os.open, and name is the filename. + + If 'suffix' is specified, the file name will end with that suffix, + otherwise there will be no suffix. + + If 'prefix' is specified, the file name will begin with that prefix, + otherwise a default prefix is used. + + If 'dir' is specified, the file will be created in that directory, + otherwise a default directory is used. + + If 'text' is specified and true, the file is opened in text + mode. Else (the default) the file is opened in binary mode. On + some operating systems, this makes no difference. + + The file is readable and writable only by the creating user ID. + If the operating system uses permission bits to indicate whether a + file is executable, the file is executable by no one. The file + descriptor is not inherited by children of this process. + + Caller is responsible for deleting the file when done with it. + """ + + if dir is None: + dir = gettempdir() + + if text: + flags = _text_openflags + else: + flags = _bin_openflags + + return _mkstemp_inner(dir, prefix, suffix, flags) + + +def mkdtemp(suffix="", prefix=template, dir=None): + """mkdtemp([suffix, [prefix, [dir]]]) + User-callable function to create and return a unique temporary + directory. The return value is the pathname of the directory. + + Arguments are as for mkstemp, except that the 'text' argument is + not accepted. + + The directory is readable, writable, and searchable only by the + creating user. + + Caller is responsible for deleting the directory when done with it. + """ + + if dir is None: + dir = gettempdir() + + names = _get_candidate_names() + + for seq in xrange(TMP_MAX): + name = names.next() + file = _os.path.join(dir, prefix + name + suffix) + try: + _os.mkdir(file, 0700) + return file + except OSError, e: + if e.errno == _errno.EEXIST: + continue # try again + raise + + raise IOError, (_errno.EEXIST, "No usable temporary directory name found") + +def mktemp(suffix="", prefix=template, dir=None): + """mktemp([suffix, [prefix, [dir]]]) + User-callable function to return a unique temporary file name. The + file is not created. + + Arguments are as for mkstemp, except that the 'text' argument is + not accepted. + + This function is unsafe and should not be used. The file name + refers to a file that did not exist at some point, but by the time + you get around to creating it, someone else may have beaten you to + the punch. + """ + +## from warnings import warn as _warn +## _warn("mktemp is a potential security risk to your program", +## RuntimeWarning, stacklevel=2) + + if dir is None: + dir = gettempdir() + + names = _get_candidate_names() + for seq in xrange(TMP_MAX): + name = names.next() + file = _os.path.join(dir, prefix + name + suffix) + if not _os.path.exists(file): + return file + + raise IOError, (_errno.EEXIST, "No usable temporary filename found") + +class _TemporaryFileWrapper: + """Temporary file wrapper + + This class provides a wrapper around files opened for + temporary use. In particular, it seeks to automatically + remove the file when it is no longer needed. + """ + + def __init__(self, file, name): + self.file = file + self.name = name + self.close_called = False + + def __getattr__(self, name): + file = self.__dict__['file'] + a = getattr(file, name) + if type(a) != type(0): + setattr(self, name, a) + return a + + # NT provides delete-on-close as a primitive, so we don't need + # the wrapper to do anything special. We still use it so that + # file.name is useful (i.e. not "(fdopen)") with NamedTemporaryFile. + if _os.name != 'nt': + + # Cache the unlinker so we don't get spurious errors at + # shutdown when the module-level "os" is None'd out. Note + # that this must be referenced as self.unlink, because the + # name TemporaryFileWrapper may also get None'd out before + # __del__ is called. + unlink = _os.unlink + + def close(self): + if not self.close_called: + self.close_called = True + self.file.close() + self.unlink(self.name) + + def __del__(self): + self.close() + +def NamedTemporaryFile(mode='w+b', bufsize=-1, suffix="", + prefix=template, dir=None): + """Create and return a temporary file. + Arguments: + 'prefix', 'suffix', 'dir' -- as for mkstemp. + 'mode' -- the mode argument to os.fdopen (default "w+b"). + 'bufsize' -- the buffer size argument to os.fdopen (default -1). + The file is created as mkstemp() would do it. + + Returns a file object; the name of the file is accessible as + file.name. The file will be automatically deleted when it is + closed. + """ + + if dir is None: + dir = gettempdir() + + if 'b' in mode: + flags = _bin_openflags + else: + flags = _text_openflags + + # Setting O_TEMPORARY in the flags causes the OS to delete + # the file when it is closed. This is only supported by Windows. + if _os.name == 'nt': + flags |= _os.O_TEMPORARY + + (fd, name) = _mkstemp_inner(dir, prefix, suffix, flags) + file = _os.fdopen(fd, mode, bufsize) + return _TemporaryFileWrapper(file, name) + +if _os.name != 'posix' or _os.sys.platform == 'cygwin': + # On non-POSIX and Cygwin systems, assume that we cannot unlink a file + # while it is open. + TemporaryFile = NamedTemporaryFile + +else: + def TemporaryFile(mode='w+b', bufsize=-1, suffix="", + prefix=template, dir=None): + """Create and return a temporary file. + Arguments: + 'prefix', 'suffix', 'directory' -- as for mkstemp. + 'mode' -- the mode argument to os.fdopen (default "w+b"). + 'bufsize' -- the buffer size argument to os.fdopen (default -1). + The file is created as mkstemp() would do it. + + Returns a file object. The file has no name, and will cease to + exist when it is closed. + """ + + if dir is None: + dir = gettempdir() + + if 'b' in mode: + flags = _bin_openflags + else: + flags = _text_openflags + + (fd, name) = _mkstemp_inner(dir, prefix, suffix, flags) + try: + _os.unlink(name) + return _os.fdopen(fd, mode, bufsize) + except: + _os.close(fd) + raise diff --git a/tools/python/xen/xend/Args.py b/tools/python/xen/xend/Args.py new file mode 100644 index 0000000000..527e841d3d --- /dev/null +++ b/tools/python/xen/xend/Args.py @@ -0,0 +1,126 @@ +import sxp + +class ArgError(StandardError): + pass + +class Args: + """Argument encoding support for HTTP. + """ + + def __init__(self, paramspec, keyspec): + self.arg_ord = [] + self.arg_dict = {} + self.key_ord = [] + self.key_dict = {} + for (name, type) in paramspec: + self.arg_ord.append(name) + self.arg_dict[name] = type + for (name, type) in keyspec: + self.key_ord.append(name) + self.key_dict[name] = type + + def get_args(self, d, xargs=None): + args = {} + keys = {} + params = [] + if xargs: + self.split_args(xargs, args, keys) + self.split_args(d, args, keys) + for a in self.arg_ord: + if a in args: + params.append(args[a]) + else: + raise ArgError('Missing parameter: %s' % a) + return (params, keys) + + def split_args(self, d, args, keys): + for (k, v) in d.items(): + if k in self.arg_dict: + type = self.arg_dict[k] + val = self.coerce(type, v) + args[k] = val + elif k in self.key_dict: + type = self.key_dict[k] + val = self.coerce(type, v) + keys[k] = val + else: + raise ArgError('Invalid parameter: %s' % k) + + def get_form_args(self, f, xargs=None): + d = {} + for (k, v) in f.items(): + n = len(v) + if ((k not in self.arg_dict) and + (k not in self.key_dict)): + continue + if n == 0: + continue + elif n == 1: + d[k] = v[0] + else: + raise ArgError('Too many values for %s' % k) + return self.get_args(d, xargs=xargs) + + def coerce(self, type, v): + try: + if type == 'int': + return int(v) + if type == 'str': + return str(v) + if type == 'sxpr': + return self.sxpr(v) + except ArgError: + raise + except StandardError, ex: + raise ArgError(str(ex)) + + def sxpr(self, v): + if instanceof(v, types.ListType): + return v + if instanceof(v, types.File) or hasattr(v, 'readline'): + return sxpr_file(v) + if instanceof(v, types.StringType): + return sxpr_file(StringIO(v)) + return str(v) + + def sxpr_file(self, fin): + try: + vals = sxp.parse(fin) + except: + raise ArgError('Coercion to sxpr failed') + if len(vals) == 1: + return vals[0] + else: + raise ArgError('Too many sxprs') + + def call_with_args(self, fn, args, xargs=None): + (params, keys) = self.get_args(args, xargs=xargs) + fn(*params, **keys) + + def call_with_form_args(self, fn, fargs, xargs=None): + (params, keys) = self.get_form_args(fargs, xargs=xargs) + fn(*params, **keys) + +class ArgFn(Args): + """Represent a remote HTTP operation as a function. + Used on the client. + """ + + def __init__(self, fn, paramspec, keyspec={}): + Args.__init__(self, paramspec, keyspec) + self.fn = fn + + def __call__(self, fargs, xargs=None): + return self.call_with_args(self.fn, fargs, xargs=xargs) + +class FormFn(Args): + """Represent an operation as a function over a form. + Used in the HTTP server. + """ + + def __init__(self, fn, paramspec, keyspec={}): + Args.__init__(self, paramspec, keyspec) + self.fn = fn + + def __call__(self, fargs, xargs=None): + return self.call_with_form_args(self.fn, fargs, xargs=xargs) diff --git a/tools/python/xen/xend/EventServer.py b/tools/python/xen/xend/EventServer.py new file mode 100644 index 0000000000..20c567ada7 --- /dev/null +++ b/tools/python/xen/xend/EventServer.py @@ -0,0 +1,215 @@ +# Copyright (C) 2004 Mike Wray +"""Simple publish/subscribe event server. + +""" +import string + +from twisted.internet import reactor + +# subscribe a.b.c h: map a.b.c -> h +# subscribe a.b.* h: map a.b.* -> h +# subscribe a.b.? h: map a.b.? -> h +# +# for event a.b.c.d: +# +# lookup a.b.c.d, call handlers +# +# lookup a.b.c.?, call handlers +# +# lookup a.b.c.d.*, call handlers +# lookup a.b.c.*, call handlers +# lookup a.b.*, call handlers +# lookup a.*, call handlers +# lookup *, call handlers + +# a.b.c.d = (a b c d) +# a.b.c.? = (a b c _) +# a.b.c.* = (a b c . _) + +class EventServer: + + DOT = '.' + QUERY = '?' + DOT_QUERY = DOT + QUERY + STAR = '*' + DOT_STAR = DOT + STAR + + def __init__(self, run=0): + self.handlers = {} + self.run = run + self.queue = [] + + def start(self): + """Enable event handling. Sends any queued events. + """ + self.run = 1 + for (e,v) in self.queue: + self.inject(e, v) + self.queue = [] + + def stop(self): + """Suspend event handling. Events injected while suspended + are queued until we are started again. + """ + self.run = 0 + + def subscribe(self, event, handler): + """Subscribe to an event. For example 'a.b.c.d'. + A subcription like 'a.b.c.?' ending in '?' matches any value + for the '?'. A subscription like 'a.b.c.*' ending in '*' matches + any event type with the same prefix, 'a.b.c' in this case. + + event event name + handler event handler fn(event, val) + """ + hl = self.handlers.get(event) + if hl is None: + self.handlers[event] = [handler] + else: + hl.append(handler) + + def unsubscribe_all(self, event=None): + """Unsubscribe all handlers for a given event, or all handlers. + + event event (optional) + """ + if event == None: + self.handlers.clear() + elif event in self.handlers: + del self.handlers[event] + + def unsubscribe(self, event, handler): + """Unsubscribe a given event and handler. + + event event + handler handler + """ + hl = self.handlers.get(event) + if hl is None: + return + if handler in hl: + hl.remove(handler) + + def inject(self, event, val, async=1): + """Inject an event. Handlers for it are called if running, otherwise + it is queued. + + event event type + val event value + """ + if self.run: + if async: + reactor.callLater(0, self.call_handlers, event, val) + else: + self.notify_handlers(event, val) + else: + self.queue.append( (event, val) ) + + def call_handlers(self, event, val): + """Internal method to call event handlers. + """ + #print ">event", event, val + self.call_event_handlers(event, event, val) + self.call_query_handlers(event, val) + self.call_star_handlers(event, val) + + def call_event_handlers(self, key, event, val): + """Call the handlers for an event. + It is safe for handlers to subscribe or unsubscribe. + + key key for handler list + event event type + val event value + """ + hl = self.handlers.get(key) + if hl is None: + return + # Copy the handler list so that handlers can call + # subscribe/unsubscribe safely - python list iteration + # is not safe against list modification. + for h in hl[:]: + try: + h(event, val) + except: + pass + + def call_query_handlers(self, event, val): + """Call regex handlers for events matching 'event' that end in '?'. + + event event type + val event value + """ + dot_idx = event.rfind(self.DOT) + if dot_idx == -1: + self.call_event_handlers(self.QUERY, event, val) + else: + event_query = event[0:dot_idx] + self.DOT_QUERY + self.call_event_handlers(event_query, event, val) + + def call_star_handlers(self, event, val): + """Call regex handlers for events matching 'event' that end in '*'. + + event event type + val event value + """ + etype = string.split(event, self.DOT) + for i in range(len(etype), 0, -1): + event_star = self.DOT.join(etype[0:i]) + self.DOT_STAR + self.call_event_handlers(event_star, event, val) + self.call_event_handlers(self.STAR, event, val) + +def instance(): + global inst + try: + inst + except: + inst = EventServer() + inst.start() + return inst + +def main(): + def sys_star(event, val): + print 'sys_star', event, val + + def sys_foo(event, val): + print 'sys_foo', event, val + s.unsubscribe('sys.foo', sys_foo) + + def sys_foo2(event, val): + print 'sys_foo2', event, val + + def sys_bar(event, val): + print 'sys_bar', event, val + + def sys_foo_bar(event, val): + print 'sys_foo_bar', event, val + + def foo_bar(event, val): + print 'foo_bar', event, val + + s = EventServer() + s.start() + s.subscribe('sys.*', sys_star) + s.subscribe('sys.foo', sys_foo) + s.subscribe('sys.foo', sys_foo2) + s.subscribe('sys.bar', sys_bar) + s.subscribe('sys.foo.bar', sys_foo_bar) + s.subscribe('foo.bar', foo_bar) + s.inject('sys.foo', 'hello') + print + s.inject('sys.bar', 'hello again') + print + s.inject('sys.foo.bar', 'hello again') + print + s.inject('foo.bar', 'hello again') + print + s.inject('foo', 'hello again') + print + s.start() + s.unsubscribe('sys.*', sys_star) + s.unsubscribe_all('sys.*') + s.inject('sys.foo', 'hello') + +if __name__ == "__main__": + main() + diff --git a/tools/python/xen/xend/EventTypes.py b/tools/python/xen/xend/EventTypes.py new file mode 100644 index 0000000000..6350baa5dd --- /dev/null +++ b/tools/python/xen/xend/EventTypes.py @@ -0,0 +1,34 @@ +# Copyright (C) 2004 Mike Wray + +## XEND_DOMAIN_CREATE = "xend.domain.create": dom +## create: +## xend.domain.destroy: dom, reason:died/crashed +## xend.domain.up ? + +## xend.domain.unpause: dom +## xend.domain.pause: dom +## xend.domain.shutdown: dom +## xend.domain.destroy: dom + +## xend.domain.migrate.begin: dom, to +## Begin tells: src host, src domain uri, dst host. Dst id known? +## err: src host, src domain uri, dst host, dst id if known, status (of domain: ok, dead,...), reason +## end: src host, src domain uri, dst host, dst uri + +## Events for both ends of migrate: for exporter and importer? +## Include migrate id so can tie together. +## Have uri /xend/migrate/ for migrate info (migrations in progress). + +## (xend.domain.migrate.begin (src ) (src.domain ) +## (dst ) (id )) + +## xend.domain.migrate.end: +## (xend.domain.migrate.end (domain ) (to ) + +## xend.node.up: xend uri +## xend.node.down: xend uri + +## xend.error ? + +## format: + diff --git a/tools/python/xen/xend/PrettyPrint.py b/tools/python/xen/xend/PrettyPrint.py new file mode 100644 index 0000000000..9e91b11448 --- /dev/null +++ b/tools/python/xen/xend/PrettyPrint.py @@ -0,0 +1,299 @@ +# Copyright (C) 2004 Mike Wray + +"""General pretty-printer, including support for SXP. + +""" +import sys +import types +import StringIO +import sxp + +class PrettyItem: + + def __init__(self, width): + self.width = width + + def insert(self, block): + block.addtoline(self) + + def get_width(self): + return self.width + + def output(self, out): + print '***PrettyItem>output>', self + pass + + def prettyprint(self, out, width): + print '***PrettyItem>prettyprint>', self + return width + +class PrettyString(PrettyItem): + + def __init__(self, x): + PrettyItem.__init__(self, len(x)) + self.value = x + + def output(self, out): + out.write(self.value) + + def prettyprint(self, line): + line.output(self) + + def show(self, out): + print >> out, ("(string (width %d) '%s')" % (self.width, self.value)) + +class PrettySpace(PrettyItem): + + def output(self, out): + out.write(' ' * self.width) + + def prettyprint(self, line): + line.output(self) + + def show(self, out): + print >> out, ("(space (width %d))" % self.width) + +class PrettyBreak(PrettyItem): + + def __init__(self, width, indent): + PrettyItem.__init__(self, width) + self.indent = indent + self.space = 0 + self.active = 0 + + def output(self, out): + out.write(' ' * self.width) + + def prettyprint(self, line): + if line.breaks(self.space): + self.active = 1 + line.newline(self.indent) + else: + line.output(self) + + def show(self, out): + print >> out, ("(break (width %d) (indent %d) (space %d) (active %d))" + % (self.width, self.indent, self.space, self.lspace, self.active)) + +class PrettyNewline(PrettySpace): + + def __init__(self, indent): + PrettySpace.__init__(self, indent) + + def insert(self, block): + block.newline() + block.addtoline(self) + + def output(self, out): + out.write(' ' * self.width) + + def prettyprint(self, line): + line.newline(0) + line.output(self) + + def show(self, out): + print >> out, ("(nl (indent %d))" % self.indent) + +class PrettyLine(PrettyItem): + def __init__(self): + PrettyItem.__init__(self, 0) + self.content = [] + + def write(self, x): + self.content.append(x) + + def end(self): + width = 0 + lastwidth = 0 + lastbreak = None + for x in self.content: + if isinstance(x, PrettyBreak): + if lastbreak: + lastbreak.space = (width - lastwidth) + lastbreak = x + lastwidth = width + width += x.get_width() + if lastbreak: + lastbreak.space = (width - lastwidth) + self.width = width + + def prettyprint(self, line): + for x in self.content: + x.prettyprint(line) + + def show(self, out): + print >> out, '(LINE (width %d)' % self.width + for x in self.content: + x.show(out) + print >> out, ')' + +class PrettyBlock(PrettyItem): + + def __init__(self, all=0, parent=None): + self.width = 0 + self.lines = [] + self.parent = parent + self.indent = 0 + self.all = all + self.broken = 0 + self.newline() + + def add(self, item): + item.insert(self) + + def end(self): + self.width = 0 + for l in self.lines: + l.end() + if self.width < l.width: + self.width = l.width + + def breaks(self, n): + return self.all and self.broken + + def newline(self): + self.lines.append(PrettyLine()) + + def addtoline(self, x): + self.lines[-1].write(x) + + def prettyprint(self, line): + self.indent = line.used + line.block = self + if not line.fits(self.width): + self.broken = 1 + for l in self.lines: + l.prettyprint(line) + line.block = self.parent + + def show(self, out): + print >> out, ('(BLOCK (width %d) (indent %d) (all %d) (broken %d)' % + (self.width, self.indent, self.all, self.broken)) + for l in self.lines: + l.show(out) + print >> out, ')' + +class Line: + + def __init__(self, out, width): + self.out = out + self.width = width + self.used = 0 + self.space = self.width + + def newline(self, indent): + indent += self.block.indent + self.out.write('\n') + self.out.write(' ' * indent) + self.used = indent + self.space = self.width - self.used + + def fits(self, n): + return self.space - n >= 0 + + def breaks(self, n): + return self.block.breaks(n) or not self.fits(n) + + def output(self, x): + n = x.get_width() + self.space -= n + self.used += n + if self.space < 0: + self.space = 0 + x.output(self.out) + +class PrettyPrinter: + """A prettyprinter based on what I remember of Derek Oppen's + prettyprint algorithm from TOPLAS way back. + """ + + def __init__(self, width=40): + self.width = width + self.block = None + self.top = None + + def write(self, x): + self.block.add(PrettyString(x)) + + def add(self, item): + self.block.add(item) + + def addbreak(self, width=1, indent=4): + self.add(PrettyBreak(width, indent)) + + def addspace(self, width=1): + self.add(PrettySpace(width)) + + def addnl(self, indent=0): + self.add(PrettyNewline(indent)) + + def begin(self, all=0): + block = PrettyBlock(all=all, parent=self.block) + self.block = block + + def end(self): + self.block.end() + if self.block.parent: + self.block.parent.add(self.block) + else: + self.top = self.block + self.block = self.block.parent + + def prettyprint(self, out=sys.stdout): + line = Line(out, self.width) + self.top.prettyprint(line) + +class SXPPrettyPrinter(PrettyPrinter): + """An SXP prettyprinter. + """ + + def pstring(self, x): + io = StringIO.StringIO() + sxp.show(x, out=io) + io.seek(0) + val = io.getvalue() + io.close() + return val + + def pprint(self, l): + if isinstance(l, types.ListType): + self.begin(all=1) + self.write('(') + i = 0 + for x in l: + if(i): self.addbreak() + self.pprint(x) + i += 1 + self.addbreak(width=0, indent=0) + self.write(')') + self.end() + else: + self.write(self.pstring(l)) + +def prettyprint(sxpr, out=sys.stdout, width=80): + """Prettyprint an SXP form. + + sxpr s-expression + out destination + width maximum output width + """ + if isinstance(sxpr, types.ListType): + pp = SXPPrettyPrinter(width=width) + pp.pprint(sxpr) + pp.prettyprint(out=out) + else: + sxp.show(sxpr, out=out) + print >> out + +def main(): + pin = sxp.Parser() + while 1: + buf = sys.stdin.read(100) + pin.input(buf) + if buf == '': break + l = pin.get_val() + prettyprint(l, width=80) + +if __name__ == "__main__": + main() + diff --git a/tools/python/xen/xend/Vifctl.py b/tools/python/xen/xend/Vifctl.py new file mode 100644 index 0000000000..49df8f6bd0 --- /dev/null +++ b/tools/python/xen/xend/Vifctl.py @@ -0,0 +1,28 @@ +import os +import os.path +import sys + +VIFCTL = '/etc/xen/xend/vifctl' + +def init(): + os.system(VIFCTL + ' init ') + +def up(vif, mac=None, bridge=None, ipaddr=[]): + args = ['vif=%s' % vif] + if mac: + args.append('mac=%s' % mac) + if bridge: + args.append('bridge=%s' % bridge) + if ipaddr: + args.append('ipaddr=%s' % ','.join(ipaddr)) + os.system(VIFCTL + ' up ' + ' '.join(args)) + +def down(vif, mac=None, bridge=None, ipaddr=[]): + args = ['vif=%s' % vif] + if mac: + args.append('mac=%s' % mac) + if bridge: + args.append('bridge=%s' % bridge) + if ipaddr: + args.append('ipaddr=%s' % ','.join(ipaddr)) + os.system(VIFCTL + ' down ' + ' '.join(args)) diff --git a/tools/python/xen/xend/XendClient.py b/tools/python/xen/xend/XendClient.py new file mode 100644 index 0000000000..13dc3dbb1e --- /dev/null +++ b/tools/python/xen/xend/XendClient.py @@ -0,0 +1,311 @@ +# Copyright (C) 2004 Mike Wray +"""Client API for the HTTP interface on xend. +Callable as a script - see main(). +""" +import sys +import httplib +import types +from StringIO import StringIO +import urlparse + +from encode import * +import sxp +import PrettyPrint + +DEBUG = 0 + +class Foo(httplib.HTTPResponse): + + def begin(self): + fin = self.fp + while(1): + buf = fin.readline() + print "***", buf + if buf == '': + print + sys.exit() + + +def sxprio(sxpr): + io = StringIO() + sxp.show(sxpr, out=io) + print >> io + io.seek(0) + return io + +def fileof(val): + """Converter for passing configs. + Handles lists, files directly. + Assumes a string is a file name and passes its contents. + """ + if isinstance(val, types.ListType): + return sxprio(val) + if isinstance(val, types.StringType): + return file(val) + if hasattr(val, 'readlines'): + return val + +# todo: need to sort of what urls/paths are using for objects. +# e.g. for domains at the moment return '0'. +# should probably return abs path w.r.t. server, e.g. /xend/domain/0. +# As an arg, assume abs path is obj uri, otherwise just id. + +# Function to convert to full url: Xend.uri(path), e.g. +# maps /xend/domain/0 to http://wray-m-3.hpl.hp.com:8000/xend/domain/0 +# And should accept urls for ids? + +def urljoin(location, root, prefix='', rest=''): + prefix = str(prefix) + rest = str(rest) + base = 'http://' + location + root + prefix + url = urlparse.urljoin(base, rest) + return url + +def nodeurl(location, root, id=''): + return urljoin(location, root, 'node/', id) + +def domainurl(location, root, id=''): + return urljoin(location, root, 'domain/', id) + +def consoleurl(location, root, id=''): + return urljoin(location, root, 'console/', id) + +def deviceurl(location, root, id=''): + return urljoin(location, root, 'device/', id) + +def vneturl(location, root, id=''): + return urljoin(location, root, 'vnet/', id) + +def eventurl(location, root, id=''): + return urljoin(location, root, 'event/', id) + +def xend_request(url, method, data=None): + urlinfo = urlparse.urlparse(url) + (uproto, ulocation, upath, uparam, uquery, ufrag) = urlinfo + if DEBUG: print url, urlinfo + if uproto != 'http': + raise StandardError('Invalid protocol: ' + uproto) + if DEBUG: print '>xend_request', ulocation, upath, method, data + (hdr, args) = encode_data(data) + if data and method == 'GET': + upath += '?' + args + args = None + if method == "POST" and upath.endswith('/'): + upath = upath[:-1] + if DEBUG: print "ulocation=", ulocation, "upath=", upath, "args=", args + #hdr['User-Agent'] = 'Mozilla' + #hdr['Accept'] = 'text/html,text/plain' + conn = httplib.HTTPConnection(ulocation) + #conn.response_class = Foo + if DEBUG: conn.set_debuglevel(1) + conn.request(method, upath, args, hdr) + resp = conn.getresponse() + if DEBUG: print resp.status, resp.reason + if DEBUG: print resp.msg.headers + if resp.status in [204, 404]: + return None + if resp.status not in [200, 201, 202, 203]: + raise RuntimeError(resp.reason) + pin = sxp.Parser() + data = resp.read() + if DEBUG: print "***data" , data + if DEBUG: print "***" + pin.input(data); + pin.input_eof() + conn.close() + val = pin.get_val() + #if isinstance(val, types.ListType) and sxp.name(val) == 'val': + # val = val[1] + if isinstance(val, types.ListType) and sxp.name(val) == 'err': + raise RuntimeError(val[1]) + if DEBUG: print '**val='; sxp.show(val); print + return val + +def xend_get(url, args=None): + return xend_request(url, "GET", args) + +def xend_call(url, data): + return xend_request(url, "POST", data) + +class Xend: + + SRV_DEFAULT = "localhost:8000" + ROOT_DEFAULT = "/xend/" + + def __init__(self, srv=None, root=None): + self.bind(srv, root) + + def bind(self, srv=None, root=None): + if srv is None: srv = self.SRV_DEFAULT + if root is None: root = self.ROOT_DEFAULT + if not root.endswith('/'): root += '/' + self.location = srv + self.root = root + + def nodeurl(self, id=''): + return nodeurl(self.location, self.root, id) + + def domainurl(self, id=''): + return domainurl(self.location, self.root, id) + + def consoleurl(self, id=''): + return consoleurl(self.location, self.root, id) + + def deviceurl(self, id=''): + return deviceurl(self.location, self.root, id) + + def vneturl(self, id=''): + return vneturl(self.location, self.root, id) + + def eventurl(self, id=''): + return eventurl(self.location, self.root, id) + + def xend(self): + return xend_get(urljoin(self.location, self.root)) + + def xend_node(self): + return xend_get(self.nodeurl()) + + def xend_node_cpu_rrobin_slice_set(self, slice): + return xend_call(self.nodeurl(), + {'op' : 'cpu_rrobin_slice_set', + 'slice' : slice }) + + def xend_node_cpu_bvt_slice_set(self, slice): + return xend_call(self.nodeurl(), + {'op' : 'cpu_bvt_slice_set', + 'slice' : slice }) + + def xend_domains(self): + return xend_get(self.domainurl()) + + def xend_domain_create(self, conf): + return xend_call(self.domainurl(), + {'op' : 'create', + 'config' : fileof(conf) }) + + def xend_domain(self, id): + return xend_get(self.domainurl(id)) + + def xend_domain_unpause(self, id): + return xend_call(self.domainurl(id), + {'op' : 'unpause'}) + + def xend_domain_pause(self, id): + return xend_call(self.domainurl(id), + {'op' : 'pause'}) + + def xend_domain_shutdown(self, id): + return xend_call(self.domainurl(id), + {'op' : 'shutdown'}) + + def xend_domain_destroy(self, id): + return xend_call(self.domainurl(id), + {'op' : 'destroy'}) + + def xend_domain_save(self, id, filename): + return xend_call(self.domainurl(id), + {'op' : 'save', + 'file' : filename}) + + def xend_domain_restore(self, id, filename): + return xend_call(self.domainurl(id), + {'op' : 'restore', + 'file' : filename }) + + def xend_domain_migrate(self, id, dst): + return xend_call(self.domainurl(id), + {'op' : 'migrate', + 'destination': dst}) + + def xend_domain_pincpu(self, id, cpu): + return xend_call(self.domainurl(id), + {'op' : 'pincpu', + 'cpu' : cpu}) + + def xend_domain_cpu_bvt_set(self, id, mcuadv, warp, warpl, warpu): + return xend_call(self.domainurl(id), + {'op' : 'cpu_bvt_set', + 'mcuadv' : mvuadv, + 'warp' : warp, + 'warpl' : warpl, + 'warpu' : warpu }) + + def xend_domain_cpu_atropos_set(self, id, period, slice, latency, xtratime): + return xend_call(self.domainurl(id), + {'op' : 'cpu_atropos_set', + 'period' : period, + 'slice' : slice, + 'latency' : latency, + 'xtratime': xtratime }) + + def xend_domain_vifs(self, id): + return xend_get(self.domainurl(id), + { 'op' : 'vifs' }) + + def xend_domain_vif_ip_add(self, id, vif, ipaddr): + return xend_call(self.domainurl(id), + {'op' : 'vif_ip_add', + 'vif' : vif, + 'ip' : ipaddr }) + + def xend_domain_vbds(self, id): + return xend_get(self.domainurl(id), + {'op' : 'vbds'}) + + def xend_domain_vbd(self, id, vbd): + return xend_get(self.domainurl(id), + {'op' : 'vbd', + 'vbd' : vbd}) + + def xend_consoles(self): + return xend_get(self.consoleurl()) + + def xend_console(self, id): + return xend_get(self.consoleurl(id)) + + def xend_vnets(self): + return xend_get(self.vneturl()) + + def xend_vnet_create(self, conf): + return xend_call(self.vneturl(), + {'op': 'create', 'config': fileof(conf) }) + + def xend_vnet(self, id): + return xend_get(self.vneturl(id)) + + def xend_vnet_delete(self, id): + return xend_call(self.vneturl(id), + {'op': 'delete'}) + + def xend_event_inject(self, sxpr): + val = xend_call(self.eventurl(), + {'op': 'inject', 'event': fileof(sxpr) }) + + +def main(argv): + """Call an API function: + + python XendClient.py fn args... + + The leading 'xend_' on the function can be omitted. + Example: + + > python XendClient.py domains + (domain 0 8) + > python XendClient.py domain 0 + (domain (id 0) (name Domain-0) (memory 128)) + """ + server = Xend() + fn = argv[1] + if not fn.startswith('xend'): + fn = 'xend_' + fn + args = argv[2:] + val = getattr(server, fn)(*args) + PrettyPrint.prettyprint(val) + print + +if __name__ == "__main__": + main(sys.argv) +else: + server = Xend() diff --git a/tools/python/xen/xend/XendConsole.py b/tools/python/xen/xend/XendConsole.py new file mode 100644 index 0000000000..4420c388f2 --- /dev/null +++ b/tools/python/xen/xend/XendConsole.py @@ -0,0 +1,179 @@ +# Copyright (C) 2004 Mike Wray + +import socket +import xen.ext.xc +xc = xen.ext.xc.new() + +import sxp +import XendRoot +xroot = XendRoot.instance() +import XendDB + +import EventServer +eserver = EventServer.instance() + +from xen.xend.server import SrvDaemon +daemon = SrvDaemon.instance() + +class XendConsoleInfo: + """Console information record. + """ + + def __init__(self, console, dom1, port1, dom2, port2, conn=None): + self.console = console + self.dom1 = int(dom1) + self.port1 = int(port1) + self.dom2 = int(dom2) + self.port2 = int(port2) + self.conn = conn + #self.id = "%d.%d-%d.%d" % (self.dom1, self.port1, self.dom2, self.port2) + self.id = str(port1) + + def __str__(self): + s = "console" + s += " id=%s" % self.id + s += " src=%d.%d" % (self.dom1, self.port1) + s += " dst=%d.%d" % (self.dom2, self.port2) + s += " port=%s" % self.console + if self.conn: + s += " conn=%s:%s" % (self.conn[0], self.conn[1]) + return s + + def sxpr(self): + sxpr = ['console', + ['id', self.id], + ['src', self.dom1, self.port1], + ['dst', self.dom2, self.port2], + ['port', self.console], + ] + if self.conn: + sxpr.append(['connected', self.conn[0], self.conn[1]]) + return sxpr + + def connection(self): + return self.conn + + def update(self, consinfo): + conn = sxp.child(consinfo, 'connected') + if conn: + self.conn = conn[1:] + else: + self.conn = None + + def uri(self): + """Get the uri to use to connect to the console. + This will be a telnet: uri. + + return uri + """ + host = socket.gethostname() + return "telnet://%s:%s" % (host, self.console) + +class XendConsole: + + dbpath = "console" + + def __init__(self): + self.db = XendDB.XendDB(self.dbpath) + self.console = {} + self.console_db = self.db.fetchall("") + if xroot.get_rebooted(): + print 'XendConsole> rebooted: removing all console info' + self.rm_all() + eserver.subscribe('xend.domain.died', self.onDomainDied) + eserver.subscribe('xend.domain.destroy', self.onDomainDied) + + def rm_all(self): + """Remove all console info. Used after reboot. + """ + for (k, v) in self.console_db.items(): + self._delete_console(k) + + def refresh(self): + consoles = daemon.consoles() + cons = {} + for consinfo in consoles: + id = str(sxp.child_value(consinfo, 'id')) + cons[id] = consinfo + if id not in self.console: + self._new_console(consinfo) + for c in self.console.values(): + consinfo = cons.get(c.id) + if consinfo: + c.update(consinfo) + else: + self._delete_console(c.id) + + def onDomainDied(self, event, val): + dom = int(val) + #print 'XendConsole>onDomainDied', 'event', event, "dom=", dom + for c in self.consoles(): + #print 'onDomainDied', "dom=", dom, "dom1=", c.dom1, "dom2=", c.dom2 + if (c.dom1 == dom) or (c.dom2 == dom): + 'XendConsole>onDomainDied', 'delete console dom=', dom + ctrl = daemon.get_domain_console(dom) + if ctrl: + ctrl.close() + self._delete_console(c.id) + + def sync(self): + self.db.saveall("", self.console_db) + + def sync_console(self, id): + self.db.save(id, self.console_db[id]) + + def _new_console(self, consinfo): + # todo: xen needs a call to get current domain id. + dom1 = 0 + port1 = sxp.child_value(consinfo, 'local_port') + dom2 = sxp.child_value(consinfo, 'domain') + port2 = sxp.child_value(consinfo, 'remote_port') + console = sxp.child_value(consinfo, 'console_port') + info = XendConsoleInfo(console, dom1, int(port1), int(dom2), int(port2)) + info.update(consinfo) + self._add_console(info.id, info) + return info + + def _add_console(self, id, info): + self.console[id] = info + self.console_db[id] = info.sxpr() + self.sync_console(id) + + def _delete_console(self, id): + if id in self.console: + del self.console[id] + if id in self.console_db: + del self.console_db[id] + self.db.delete(id) + + def console_ls(self): + self.refresh() + return self.console.keys() + + def consoles(self): + self.refresh() + return self.console.values() + + def console_create(self, dom): + consinfo = daemon.console_create(dom) + info = self._new_console(consinfo) + return info + + def console_get(self, id): + self.refresh() + return self.console.get(id) + + def console_delete(self, id): + self._delete_console(id) + + def console_disconnect(self, id): + id = int(id) + daemon.console_disconnect(id) + +def instance(): + global inst + try: + inst + except: + inst = XendConsole() + return inst diff --git a/tools/python/xen/xend/XendDB.py b/tools/python/xen/xend/XendDB.py new file mode 100644 index 0000000000..6a27e65b58 --- /dev/null +++ b/tools/python/xen/xend/XendDB.py @@ -0,0 +1,91 @@ +# Copyright (C) 2004 Mike Wray + +import os +import os.path +import errno +import dircache +import time + +import sxp +import XendRoot +xroot = XendRoot.instance() + +class XendDB: + """Persistence for Xend. Stores data in files and directories. + """ + + def __init__(self, path=None): + self.dbpath = xroot.get_dbroot() + if path: + self.dbpath = os.path.join(self.dbpath, path) + pass + + def filepath(self, path): + return os.path.join(self.dbpath, path) + + def fetch(self, path): + fpath = self.filepath(path) + return self.fetchfile(fpath) + + def fetchfile(self, fpath): + pin = sxp.Parser() + fin = file(fpath, "rb") + try: + while 1: + try: + buf = fin.read(1024) + except IOError, ex: + if ex.errno == errno.EINTR: + continue + else: + raise + pin.input(buf) + if buf == '': + pin.input_eof() + break + finally: + fin.close() + return pin.get_val() + + def save(self, path, sxpr): + fpath = self.filepath(path) + return self.savefile(fpath, sxpr) + + def savefile(self, fpath, sxpr): + fdir = os.path.dirname(fpath) + if not os.path.isdir(fdir): + os.makedirs(fdir) + fout = file(fpath, "wb+") + try: + t = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + fout.write("# %s %s\n" % (fpath, t)) + sxp.show(sxpr, out=fout) + finally: + fout.close() + + def fetchall(self, path): + dpath = self.filepath(path) + d = {} + for k in dircache.listdir(dpath): + try: + v = self.fetchfile(os.path.join(dpath, k)) + d[k] = v + except: + pass + return d + + def saveall(self, path, d): + for (k, v) in d.items(): + self.save(os.path.join(path, k), v) + + def delete(self, path): + dpath = self.filepath(path) + os.unlink(dpath) + + def ls(self, path): + dpath = self.filepath(path) + return dircache.listdir(dpath) + + + + diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py new file mode 100644 index 0000000000..3aaf080c36 --- /dev/null +++ b/tools/python/xen/xend/XendDomain.py @@ -0,0 +1,369 @@ +# Copyright (C) 2004 Mike Wray + +"""Handler for domain operations. + Nothing here is persistent (across reboots). + Needs to be persistent for one uptime. +""" +import sys + +from twisted.internet import defer + +import xen.ext.xc; xc = xen.ext.xc.new() + +import sxp +import XendRoot +xroot = XendRoot.instance() +import XendDB +import XendDomainInfo +import XendConsole +import EventServer + +from xen.xend.server import SrvDaemon +xend = SrvDaemon.instance() + +eserver = EventServer.instance() + +__all__ = [ "XendDomain" ] + +class XendDomain: + """Index of all domains. Singleton. + """ + + dbpath = "domain" + domain = {} + + def __init__(self): + self.xconsole = XendConsole.instance() + # Table of domain info indexed by domain id. + self.db = XendDB.XendDB(self.dbpath) + #self.domain = {} + self.domain_db = self.db.fetchall("") + if xroot.get_rebooted(): + print 'XendDomain> rebooted: removing all domain info' + self.rm_all() + eserver.subscribe('xend.virq', self.onVirq) + self.initial_refresh() + + def onVirq(self, event, val): + print 'XendDomain> virq', val + self.reap() + + def rm_all(self): + """Remove all domain info. Used after reboot. + """ + for (k, v) in self.domain_db.items(): + self._delete_domain(k, notify=0) + + def initial_refresh(self): + """Refresh initial domain info from domain_db. + """ + print "initial_refresh>" + for d in self.domain_db.values(): print 'db dom=', d + domlist = xc.domain_getinfo() + for d in domlist: print 'xc dom=', d + doms = {} + for d in domlist: + domid = str(d['dom']) + doms[domid] = d + dlist = [] + for config in self.domain_db.values(): + domid = str(sxp.child_value(config, 'id')) + print "dom=", domid, "config=", config + if domid in doms: + print "dom=", domid, "new" + deferred = self._new_domain(config, doms[domid]) + dlist.append(deferred) + else: + print "dom=", domid, "del" + self._delete_domain(domid) + deferred = defer.DeferredList(dlist, fireOnOneErrback=1) + def cbok(val): + #print "doms:" + #for d in self.domain.values(): print 'dom', d + self.refresh() + print "XendDomain>initial_refresh> doms:" + for d in self.domain.values(): print 'dom', d + deferred.addCallback(cbok) + + def sync(self): + """Sync domain db to disk. + """ + self.db.saveall("", self.domain_db) + + def sync_domain(self, dom): + """Sync info for a domain to disk. + + dom domain id (string) + """ + self.db.save(dom, self.domain_db[dom]) + + def close(self): + pass + + def _new_domain(self, savedinfo, info): + """Create a domain entry from saved info. + """ +## console = None +## kernel = None +## id = sxp.child_value(info, 'id') +## dom = int(id) +## name = sxp.child_value(info, 'name') +## memory = int(sxp.child_value(info, 'memory')) +## consoleinfo = sxp.child(info, 'console') +## if consoleinfo: +## consoleid = sxp.child_value(consoleinfo, 'id') +## console = self.xconsole.console_get(consoleid) +## if dom and console is None: +## # Try to connect a console. +## console = self.xconsole.console_create(dom) +## config = sxp.child(info, 'config') +## if config: +## image = sxp.child(info, 'image') +## if image: +## image = sxp.child0(image) +## kernel = sxp.child_value(image, 'kernel') +## dominfo = XendDomainInfo.XendDomainInfo( +## config, dom, name, memory, kernel, console) + config = sxp.child_value(savedinfo, 'config') + deferred = XendDomainInfo.vm_recreate(config, info) + def fn(dominfo): + self.domain[dominfo.id] = dominfo + deferred.addCallback(fn) + return deferred + + def _add_domain(self, id, info, notify=1): + self.domain[id] = info + self.domain_db[id] = info.sxpr() + self.sync_domain(id) + if notify: eserver.inject('xend.domain.created', id) + + def _delete_domain(self, id, notify=1): + if id in self.domain: + if notify: eserver.inject('xend.domain.died', id) + del self.domain[id] + if id in self.domain_db: + del self.domain_db[id] + self.db.delete(id) + + def reap(self): + """Go through the domains looking for ones that have crashed or stopped. + Tidy them up. + """ + print 'XendDomain>reap>' + domlist = xc.domain_getinfo() + casualties = [] + for d in domlist: + #print 'dom', d + dead = 0 + dead = dead or (d['crashed'] or d['shutdown']) + dead = dead or (d['dying'] and + not(d['running'] or d['paused'] or d['blocked'])) + if dead: + casualties.append(d) + for d in casualties: + id = str(d['dom']) + print 'XendDomain>reap> died id=', id, d + dominfo = self.domain.get(id) + if not dominfo: continue + dominfo.died() + self.domain_destroy(id, refresh=0) + print 'XendDomain>reap<' + + def refresh(self): + """Refresh domain list from Xen. + """ + domlist = xc.domain_getinfo() + # Index the domlist by id. + # Add entries for any domains we don't know about. + doms = {} + for d in domlist: + id = str(d['dom']) + doms[id] = d + if id not in self.domain: + config = None + #image = None + #newinfo = XendDomainInfo.XendDomainInfo( + # config, d['dom'], d['name'], d['mem_kb']/1024, image=image, info=d) + deferred = XendDomainInfo.vm_recreate(config, d) + def fn(dominfo): + self._add_domain(dominfo.id, dominfo) + deferred.addCallback(fn) + # Remove entries for domains that no longer exist. + for d in self.domain.values(): + dominfo = doms.get(d.id) + if dominfo: + d.update(dominfo) + else: + self._delete_domain(d.id) + self.reap() + + def refresh_domain(self, id): + dom = int(id) + dominfo = xc.domain_getinfo(dom, 1) + if dominfo == [] or dominfo[0]['dom'] != dom: + try: + self._delete_domain(id) + except: + print 'refresh_domain: error' + raise + pass + else: + d = self.domain.get(id) + if d: + d.update(dominfo[0]) + + def domain_ls(self): + # List domains. + # Update info from kernel first. + self.refresh() + return self.domain.keys() + + def domains(self): + self.refresh() + return self.domain.values() + + def domain_create(self, config): + # Create domain, log it. + deferred = XendDomainInfo.vm_create(config) + def fn(dominfo): + self._add_domain(dominfo.id, dominfo) + return dominfo + deferred.addCallback(fn) + return deferred + + def domain_get(self, id): + id = str(id) + self.refresh_domain(id) + return self.domain.get(id) + + def domain_unpause(self, id): + """(Re)start domain running. + """ + dom = int(id) + eserver.inject('xend.domain.unpause', id) + return xc.domain_unpause(dom=dom) + + def domain_pause(self, id): + """Pause domain execution. + """ + dom = int(id) + eserver.inject('xend.domain.pause', id) + return xc.domain_pause(dom=dom) + + def domain_shutdown(self, id, reason='poweroff'): + """Shutdown domain (nicely). + """ + dom = int(id) + if dom <= 0: + return 0 + eserver.inject('xend.domain.shutdown', [id, reason]) + val = xend.domain_shutdown(dom, reason) + self.refresh() + return val + + def domain_destroy(self, id, refresh=1): + """Terminate domain immediately. + """ + dom = int(id) + if dom <= 0: + return 0 + eserver.inject('xend.domain.destroy', id) + val = xc.domain_destroy(dom=dom) + if refresh: self.refresh() + return val + + def domain_migrate(self, id, dst): + """Start domain migration. + """ + # Need a cancel too? + pass + + def domain_save(self, id, dst, progress=0): + """Save domain state to file, destroy domain. + """ + dom = int(id) + dominfo = self.domain_get(id) + if not dominfo: + return -1 + vmconfig = sxp.to_string(dominfo.sxpr()) + self.domain_pause(id) + eserver.inject('xend.domain.save', id) + rc = xc.linux_save(dom=dom, state_file=dst, vmconfig=vmconfig, progress=progress) + if rc == 0: + self.domain_destroy(id) + return rc + + def domain_restore(self, src, progress=0): + """Restore domain from file. + """ + dominfo = XendDomainInfo.vm_restore(src, progress=progress) + self._add_domain(dominfo.id, dominfo) + return dominfo + + #============================================================================ + # Backward compatibility stuff from here on. + + def domain_pincpu(self, dom, cpu): + dom = int(dom) + return xc.domain_pincpu(dom, cpu) + + def domain_cpu_bvt_set(self, dom, mcuadv, warp, warpl, warpu): + dom = int(dom) + return xc.bvtsched_domain_set(dom=dom, mcuadv=mcuadv, + warp=warp, warpl=warpl, warpu=warpu) + + def domain_cpu_bvt_get(self, dom): + dom = int(dom) + return xc.bvtsched_domain_get(dom) + + def domain_cpu_atropos_set(self, dom, period, slice, latency, xtratime): + dom = int(dom) + return xc.atropos_domain_set(dom, period, slice, latency, xtratime) + + def domain_cpu_atropos_get(self, dom): + dom = int(dom) + return xc.atropos_domain_get(dom) + + def domain_vif_ls(self, dom): + dominfo = self.domain_get(dom) + if not dominfo: return None + devs = dominfo.get_devices('vif') + return range(0, len(devs)) + + def domain_vif_get(self, dom, vif): + dominfo = self.domain_get(dom) + if not dominfo: return None + return dominfo.get_device_by_index(vif) + +## def domain_vif_ip_add(self, dom, vif, ip): +## dom = int(dom) +## return xenctl.ip.setup_vfr_rules_for_vif(dom, vif, ip) + + def domain_vbd_ls(self, dom): + dominfo = self.domain_get(dom) + if not dominfo: return [] + devs = dominfo.get_devices('vbd') + return [ sxp.child_value(v, 'dev') for v in devs ] + + def domain_vbd_get(self, dom, vbd): + dominfo = self.domain_get(dom) + if not dominfo: return None + devs = dominfo.get_devices('vbd') + for v in devs: + if sxp.child_value(v, 'dev') == vbd: + return v + return None + + def domain_shadow_control(self, dom, op): + dom = int(dom) + return xc.shadow_control(dom, op) + + #============================================================================ + +def instance(): + global inst + try: + inst + except: + inst = XendDomain() + return inst diff --git a/tools/python/xen/xend/XendDomainConfig.py b/tools/python/xen/xend/XendDomainConfig.py new file mode 100644 index 0000000000..35db31ff51 --- /dev/null +++ b/tools/python/xen/xend/XendDomainConfig.py @@ -0,0 +1,44 @@ +# Copyright (C) 2004 Mike Wray + +"""Handler for persistent domain configs. + +""" + +import sxp +import XendDB +import XendDomain + +__all__ = [ "XendDomainConfig" ] + +class XendDomainConfig: + + dbpath = 'config' + + def __init__(self): + self.db = XendDB.XendDB(self.dbpath) + + def domain_config_ls(self, path): + return self.db.ls(path) + + def domain_config_create(self, path, sxpr): + self.db.save(path, sxpr) + pass + + def domain_config_delete(self, path): + self.db.delete(path) + + def domain_config_instance(self, path): + """Create a domain from a config. + """ + config = self.db.fetch(path) + xd = XendDomain.instance() + newdom = xd.domain_create(config) + return newdom + +def instance(): + global inst + try: + inst + except: + inst = XendDomainConfig() + return inst diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py new file mode 100644 index 0000000000..a7e5aa3b2f --- /dev/null +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -0,0 +1,908 @@ +#!/usr/bin/python +# Copyright (C) 2004 Mike Wray + +"""Representation of a single domain. +Includes support for domain construction, using +open-ended configurations. + +Author: Mike Wray + +""" + +import string +import re +import sys +import os + +from twisted.internet import defer + +import xen.ext.xc; xc = xen.ext.xc.new() +import xen.util.ip + +import sxp + +import XendConsole +xendConsole = XendConsole.instance() + +import server.SrvDaemon +xend = server.SrvDaemon.instance() + +SIF_BLK_BE_DOMAIN = (1<<4) +SIF_NET_BE_DOMAIN = (1<<5) + +def readlines(fd): + """Version of readlines safe against EINTR. + """ + import errno + + lines = [] + while 1: + try: + line = fd.readline() + except IOError, ex: + if ex.errno == errno.EINTR: + continue + else: + raise + if line == '': break + lines.append(line) + return lines + +class VmError(ValueError): + """Vm construction error.""" + + def __init__(self, value): + self.value = value + + def __str__(self): + return self.value + + +def blkdev_name_to_number(name): + """Take the given textual block-device name (e.g., '/dev/sda1', + 'hda') and return the device number used by the OS. """ + + if not re.match( '/dev/', name ): + name = '/dev/' + name + + return os.stat(name).st_rdev + +def lookup_raw_partn(partition): + """Take the given block-device name (e.g., '/dev/sda1', 'hda') + and return a dictionary { device, start_sector, + nr_sectors, type } + device: Device number of the given partition + start_sector: Index of first sector of the partition + nr_sectors: Number of sectors comprising this partition + type: 'Disk' or identifying name for partition type + """ + + if not re.match( '/dev/', partition ): + partition = '/dev/' + partition + + drive = re.split( '[0-9]', partition )[0] + + if drive == partition: + fd = os.popen( '/sbin/sfdisk -s ' + drive + ' 2>/dev/null' ) + line = readline(fd) + if line: + return [ { 'device' : blkdev_name_to_number(drive), + 'start_sector' : long(0), + 'nr_sectors' : long(line) * 2, + 'type' : 'Disk' } ] + return None + + # determine position on disk + fd = os.popen( '/sbin/sfdisk -d ' + drive + ' 2>/dev/null' ) + + #['/dev/sda3 : start= 16948575, size=16836120, Id=83, bootable\012'] + lines = readlines(fd) + for line in lines: + m = re.search( '^' + partition + '\s*: start=\s*([0-9]+), ' + + 'size=\s*([0-9]+), Id=\s*(\S+).*$', line) + if m: + return [ { 'device' : blkdev_name_to_number(drive), + 'start_sector' : long(m.group(1)), + 'nr_sectors' : long(m.group(2)), + 'type' : m.group(3) } ] + + return None + +def lookup_disk_uname(uname): + """Lookup a list of segments for a physical device. + uname [string]: name of the device in the format \'phy:dev\' for a physical device + returns [list of dicts]: list of extents that make up the named device + """ + ( type, d_name ) = string.split( uname, ':' ) + + if type == "phy": + segments = lookup_raw_partn( d_name ) + else: + segments = None + return segments + +def make_disk(dom, uname, dev, mode, recreate=0): + """Create a virtual disk device for a domain. + + @returns Deferred + """ + segments = lookup_disk_uname(uname) + if not segments: + raise VmError("vbd: Segments not found: uname=%s" % uname) + if len(segments) > 1: + raise VmError("vbd: Multi-segment vdisk: uname=%s" % uname) + segment = segments[0] + vdev = blkdev_name_to_number(dev) + ctrl = xend.blkif_create(dom, recreate=recreate) + + def fn(ctrl): + return xend.blkif_dev_create(dom, vdev, mode, segment, recreate=recreate) + ctrl.addCallback(fn) + return ctrl + +def make_vif(dom, vif, vmac, recreate=0): + """Create a virtual network device for a domain. + + + @returns Deferred + """ + xend.netif_create(dom, recreate=recreate) + d = xend.netif_dev_create(dom, vif, vmac, recreate=recreate) + return d + +def vif_up(iplist): + """send an unsolicited ARP reply for all non link-local IP addresses. + + iplist IP addresses + """ + + IP_NONLOCAL_BIND = '/proc/sys/net/ipv4/ip_nonlocal_bind' + + def get_ip_nonlocal_bind(): + return int(open(IP_NONLOCAL_BIND, 'r').read()[0]) + + def set_ip_nonlocal_bind(v): + print >> open(IP_NONLOCAL_BIND, 'w'), str(v) + + def link_local(ip): + return xen.util.ip.check_subnet(ip, '169.254.0.0', '255.255.0.0') + + def arping(ip, gw): + cmd = '/usr/sbin/arping -A -b -I eth0 -c 1 -s %s %s' % (ip, gw) + print cmd + os.system(cmd) + + gateway = xen.util.ip.get_current_ipgw() or '255.255.255.255' + nlb = get_ip_nonlocal_bind() + if not nlb: set_ip_nonlocal_bind(1) + try: + for ip in iplist: + if not link_local(ip): + arping(ip, gateway) + finally: + if not nlb: set_ip_nonlocal_bind(0) + +config_handlers = {} + +def add_config_handler(name, h): + """Add a handler for a config field. + + name field name + h handler: fn(vm, config, field, index) + """ + config_handlers[name] = h + +def get_config_handler(name): + """Get a handler for a config field. + + returns handler or None + """ + return config_handlers.get(name) + +"""Table of handlers for virtual machine images. +Indexed by image type. +""" +image_handlers = {} + +def add_image_handler(name, h): + """Add a handler for an image type + name image type + h handler: fn(config, name, memory, image) + """ + image_handlers[name] = h + +def get_image_handler(name): + """Get the handler for an image type. + name image type + + returns handler or None + """ + return image_handlers.get(name) + +"""Table of handlers for devices. +Indexed by device type. +""" +device_handlers = {} + +def add_device_handler(name, h): + """Add a handler for a device type. + + name device type + h handler: fn(vm, dev) + """ + device_handlers[name] = h + +def get_device_handler(name): + """Get the handler for a device type. + + name device type + + returns handler or None + """ + return device_handlers.get(name) + +def vm_create(config): + """Create a VM from a configuration. + If a vm has been partially created and there is an error it + is destroyed. + + config configuration + + returns Deferred + raises VmError for invalid configuration + """ + print 'vm_create>' + vm = XendDomainInfo() + return vm.construct(config) + +def vm_recreate(config, info): + """Create the VM object for an existing domain. + """ + vm = XendDomainInfo() + vm.recreate = 1 + vm.setdom(info['dom']) + vm.name = info['name'] + vm.memory = info['mem_kb']/1024 + if config: + d = vm.construct(config) + else: + d = defer.Deferred() + d.callback(vm) + return d + +def vm_restore(src, progress=0): + """Restore a VM from a disk image. + + src saved state to restore + progress progress reporting flag + returns deferred + raises VmError for invalid configuration + """ + vm = XendDomainInfo() + ostype = "linux" #todo Set from somewhere (store in the src?). + restorefn = getattr(xc, "%s_restore" % ostype) + d = restorefn(state_file=src, progress=progress) + dom = int(d['dom']) + if dom < 0: + raise VMError('restore failed') + vmconfig = sxp.from_string(d['vmconfig']) + vm.config = sxp.child_value(vmconfig, 'config') + deferred = vm.dom_configure(dom) + def vifs_cb(val, vm): + vif_up(vm.ipaddrs) + deferred.addCallback(vifs_cb, vm) + return deferred + +def dom_get(dom): + domlist = xc.domain_getinfo(dom=dom) + if domlist and dom == domlist[0]['dom']: + return domlist[0] + return None + + +def append_deferred(dlist, v): + if isinstance(v, defer.Deferred): + dlist.append(v) + +def _vm_configure1(val, vm): + d = vm.create_devices() + print '_vm_configure1> made devices...' + def cbok(x): + print '_vm_configure1> cbok', x + return x + d.addCallback(cbok) + d.addCallback(_vm_configure2, vm) + print '_vm_configure1<' + return d + +def _vm_configure2(val, vm): + print '>callback _vm_configure2...' + d = vm.configure_fields() + def cbok(results): + print '_vm_configure2> cbok', results + return vm + def cberr(err): + print '_vm_configure2> cberr', err + vm.destroy() + return err + d.addCallback(cbok) + d.addErrback(cberr) + print '<_vm_configure2' + return d + +class XendDomainInfo: + """Virtual machine object.""" + + def __init__(self): + self.recreate = 0 + self.config = None + self.id = None + self.dom = None + self.name = None + self.memory = None + self.image = None + self.ramdisk = None + self.cmdline = None + self.console = None + self.devices = {} + self.configs = [] + self.info = None + self.ipaddrs = [] + self.blkif_backend = 0 + self.netif_backend = 0 + #todo: state: running, suspended + self.state = 'running' + #todo: set to migrate info if migrating + self.migrate = None + + def setdom(self, dom): + self.dom = int(dom) + self.id = str(dom) + + def update(self, info): + """Update with info from xc.domain_getinfo(). + """ + self.info = info + self.memory = self.info['mem_kb'] / 1024 + + def __str__(self): + s = "domain" + s += " id=" + self.id + s += " name=" + self.name + s += " memory=" + str(self.memory) + if self.console: + s += " console=" + self.console.id + if self.image: + s += " image=" + self.image + s += "" + return s + + __repr__ = __str__ + + def sxpr(self): + sxpr = ['domain', + ['id', self.id], + ['name', self.name], + ['memory', self.memory] ] + if self.info: + run = (self.info['running'] and 'r') or '-' + block = (self.info['blocked'] and 'b') or '-' + stop = (self.info['paused'] and 'p') or '-' + susp = (self.info['shutdown'] and 's') or '-' + crash = (self.info['crashed'] and 'c') or '-' + state = run + block + stop + susp + crash + sxpr.append(['state', state]) + if self.info['shutdown']: + reasons = ["poweroff", "reboot", "suspend"] + reason = reasons[self.info['shutdown_reason']] + sxpr.append(['shutdown_reason', reason]) + sxpr.append(['cpu', self.info['cpu']]) + sxpr.append(['cpu_time', self.info['cpu_time']/1e9]) + if self.console: + sxpr.append(self.console.sxpr()) + if self.config: + sxpr.append(['config', self.config]) + return sxpr + + def construct(self, config): + # todo - add support for scheduling params? + self.config = config + try: + self.name = sxp.child_value(config, 'name') + self.memory = int(sxp.child_value(config, 'memory', '128')) + self.configure_backends() + image = sxp.child_value(config, 'image') + image_name = sxp.name(image) + image_handler = get_image_handler(image_name) + if image_handler is None: + raise VmError('unknown image type: ' + image_name) + image_handler(self, image) + deferred = self.configure() + except StandardError, ex: + # Catch errors, cleanup and re-raise. + self.destroy() + raise + def cbok(x): + print 'vm_create> cbok', x + return x + deferred.addCallback(cbok) + print 'vm_create<' + return deferred + + def config_devices(self, name): + """Get a list of the 'device' nodes of a given type from the config. + + name device type + return list of device configs + """ + devices = [] + for d in sxp.children(self.config, 'device'): + dev = sxp.child0(d) + if dev is None: continue + if name == sxp.name(dev): + devices.append(dev) + return devices + + def add_device(self, type, dev): + """Add a device to a virtual machine. + + dev device to add + """ + dl = self.devices.get(type, []) + dl.append(dev) + self.devices[type] = dl + + def get_devices(self, type): + val = self.devices.get(type, []) + return val + + def get_device_by_id(self, type, id): + """Get the device with the given id. + + id device id + + returns device or None + """ + dl = self.get_devices(type) + for d in dl: + if d.getprop('id') == id: + return d + return None + + def get_device_by_index(self, type, idx): + """Get the device with the given index. + + idx device index + + returns device or None + """ + dl = self.get_devices(type) + if 0 <= idx < len(dl): + return dl[idx] + else: + return None + + def add_config(self, val): + """Add configuration data to a virtual machine. + + val data to add + """ + self.configs.append(val) + + def destroy(self): + if self.dom <= 0: + return 0 + return xc.domain_destroy(dom=self.dom) + + def died(self): + print 'died>', self.dom + self.release_devices() + + def release_devices(self): + print 'release_devices>', self.dom + self.release_vifs() + self.release_vbds() + self.devices = {} + + def release_vifs(self): + print 'release_vifs>', self.dom + if self.dom is None: return + ctrl = xend.netif_get(self.dom) + if ctrl: + ctrl.destroy() + + def release_vbds(self): + print 'release_vbds>', self.dom + if self.dom is None: return + ctrl = xend.blkif_get(self.dom) + if ctrl: + ctrl.destroy() + + def show(self): + """Print virtual machine info. + """ + print "[VM dom=%d name=%s memory=%d" % (self.dom, self.name, self.memory) + print "image:" + sxp.show(self.image) + print + for dl in self.devices: + for dev in dl: + print "device:" + sxp.show(dev) + print + for val in self.configs: + print "config:" + sxp.show(val) + print + print "]" + + def init_domain(self): + """Initialize the domain memory. + """ + if self.recreate: return + memory = self.memory + name = self.name + cpu = int(sxp.child_value(self.config, 'cpu', '-1')) + print 'init_domain>', memory, name, cpu + dom = xc.domain_create(mem_kb= memory * 1024, name= name, cpu= cpu) + if dom <= 0: + raise VmError('Creating domain failed: name=%s memory=%d' + % (name, memory)) + self.setdom(dom) + + def build_domain(self, ostype, kernel, ramdisk, cmdline, vifs_n): + """Build the domain boot image. + """ + if self.recreate: return + if len(cmdline) >= 256: + print 'Warning: kernel cmdline too long' + dom = self.dom + buildfn = getattr(xc, '%s_build' % ostype) + print 'build_domain>', ostype, dom, kernel, cmdline, ramdisk + flags = 0 + if self.netif_backend: flags |= SIF_NET_BE_DOMAIN + if self.blkif_backend: flags |= SIF_BLK_BE_DOMAIN + err = buildfn(dom = dom, + image = kernel, + control_evtchn = self.console.port2, + cmdline = cmdline, + ramdisk = ramdisk, + flags = flags) + if err != 0: + raise VmError('Building domain failed: type=%s dom=%d err=%d' + % (ostype, dom, err)) + + def create_domain(self, ostype, kernel, ramdisk, cmdline, vifs_n): + """Create a domain. Builds the image but does not configure it. + + ostype OS type + kernel kernel image + ramdisk kernel ramdisk + cmdline kernel commandline + vifs_n number of network interfaces + """ + print 'create_domain>', ostype, kernel + if not self.recreate: + if not os.path.isfile(kernel): + raise VmError('Kernel image does not exist: %s' % kernel) + if ramdisk and not os.path.isfile(ramdisk): + raise VMError('Kernel ramdisk does not exist: %s' % ramdisk) + print 'create-domain> init_domain...' + self.init_domain() + print 'create_domain>', 'dom=', self.dom + self.console = xendConsole.console_create(self.dom) + self.build_domain(ostype, kernel, ramdisk, cmdline, vifs_n) + self.image = kernel + self.ramdisk = ramdisk + self.cmdline = cmdline + + def create_devices(self): + """Create the devices for a vm. + + returns Deferred + raises VmError for invalid devices + """ + print '>create_devices' + dlist = [] + devices = sxp.children(self.config, 'device') + index = {} + for d in devices: + dev = sxp.child0(d) + if dev is None: + raise VmError('invalid device') + dev_name = sxp.name(dev) + dev_index = index.get(dev_name, 0) + dev_handler = get_device_handler(dev_name) + if dev_handler is None: + raise VmError('unknown device type: ' + dev_name) + v = dev_handler(self, dev, dev_index) + append_deferred(dlist, v) + index[dev_name] = dev_index + 1 + deferred = defer.DeferredList(dlist, fireOnOneErrback=1) + print ' created', dev + return id + defer.addCallback(fn) + return defer + +def vm_dev_vbd(vm, val, index): + """Create a virtual block device (vbd). + + vm virtual machine + val vbd config + index vbd index + """ + if vm.blkif_backend: + raise VmError('vbd: vbd in blkif backend domain') + vdev = index + uname = sxp.child_value(val, 'uname') + if not uname: + raise VMError('vbd: Missing uname') + dev = sxp.child_value(val, 'dev') + if not dev: + raise VMError('vbd: Missing dev') + mode = sxp.child_value(val, 'mode', 'r') + defer = make_disk(vm.dom, uname, dev, mode, vm.recreate) + def fn(vbd): + dev = xend.blkif_dev(vm.dom, vdev) + vm.add_device('vbd', dev) + return vbd + defer.addCallback(fn) + return defer + +def parse_pci(val): + if isinstance(val, StringType): + radix = 10 + if val.startswith('0x') or val.startswith('0X'): + radix = 16 + v = int(val, radix) + else: + v = val + return v + +def vm_dev_pci(vm, val, index): + bus = sxp.child_value(val, 'bus') + if not bus: + raise VMError('pci: Missing bus') + dev = sxp.child_value(val, 'dev') + if not dev: + raise VMError('pci: Missing dev') + func = sxp.child_value(val, 'func') + if not func: + raise VMError('pci: Missing func') + try: + bus = parse_pci(bus) + dev = parse_pci(dev) + func = parse_pci(func) + except: + raise VMError('pci: invalid parameter') + rc = xc.physdev_pci_access_modify(dom=vm.dom, bus=bus, dev=dev, + func=func, enable=1) + if rc < 0: + #todo non-fatal + raise VMError('pci: Failed to configure device: bus=%s dev=%s func=%s' % + (bus, dev, func)) + return rc + + +def vm_field_vfr(vm, config, val, index): + """Handle a vfr field in a config. + + vm virtual machine + config vm config + val vfr field + """ + # Get the rules and add them. + # (vfr (vif (id foo) (ip x.x.x.x)) ... ) + list = sxp.children(val, 'vif') + ipaddrs = [] + for v in list: + id = sxp.child_value(v, 'id') + if id is None: + raise VmError('vfr: missing vif id') + id = int(id) + dev = vm.get_device_by_index('vif', id) + if not dev: + raise VmError('vfr: invalid vif id %d' % id) + vif = sxp.child_value(dev, 'vif') + ip = sxp.child_value(v, 'ip') + if not ip: + raise VmError('vfr: missing ip address') + ipaddrs.append(ip); + # todo: Configure the ipaddrs. + vm.ipaddrs = ipaddrs + +def vnet_bridge(vnet, vmac, dom, idx): + """Add the device for the vif to the bridge for its vnet. + """ + vif = "vif%d.%d" % (dom, idx) + try: + cmd = "(vif.conn (vif %s) (vnet %s) (vmac %s))" % (vif, vnet, vmac) + print "*** vnet_bridge>", cmd + out = file("/proc/vnet/policy", "wb") + out.write(cmd) + err = out.close() + print "vnet_bridge>", "err=", err + except IOError, ex: + print "vnet_bridge>", ex + +def vm_field_vnet(vm, config, val, index): + """Handle a vnet field in a config. + + vm virtual machine + config vm config + val vnet field + index index + """ + # Get the vif children. For each vif look up the vif device + # with the given id and configure its vnet. + # (vnet (vif (id foo) (vnet 2) (mac x:x:x:x:x:x)) ... ) + vif_vnets = sxp.children(val, 'vif') + for v in vif_vnets: + id = sxp.child_value(v, 'id') + if id is None: + raise VmError('vnet: missing vif id') + dev = vm.get_device_by_id('vif', id) + #vnet = sxp.child_value(v, 'vnet', 1) + #mac = sxp.child_value(dev, 'mac') + #vif = sxp.child_value(dev, 'vif') + #vnet_bridge(vnet, mac, vm.dom, 0) + #vm.add_config([ 'vif.vnet', ['id', id], ['vnet', vnet], ['mac', mac]]) + +# Register image handlers for linux and bsd. +add_image_handler('linux', vm_image_linux) +add_image_handler('netbsd', vm_image_netbsd) + +# Register device handlers for vifs and vbds. +add_device_handler('vif', vm_dev_vif) +add_device_handler('vbd', vm_dev_vbd) +add_device_handler('pci', vm_dev_pci) + +# Register config handlers for vfr and vnet. +add_config_handler('vfr', vm_field_vfr) +add_config_handler('vnet', vm_field_vnet) diff --git a/tools/python/xen/xend/XendMigrate.py b/tools/python/xen/xend/XendMigrate.py new file mode 100644 index 0000000000..1580ba83ed --- /dev/null +++ b/tools/python/xen/xend/XendMigrate.py @@ -0,0 +1,103 @@ +# Copyright (C) 2004 Mike Wray + +import sys +import socket + +import sxp +import XendDB +import EventServer; eserver = EventServer.instance() + +class XendMigrateInfo: + + # states: begin, active, failed, succeeded? + + def __init__(self, id, dom, dst): + self.id = id + self.state = 'begin' + self.src_host = socket.gethostname() + self.src_dom = dom + self.dst_host = dst + self.dst_dom = None + + def set_state(self, state): + self.state = state + + def get_state(self): + return self.state + + def sxpr(self): + sxpr = ['migrate', ['id', self.id], ['state', self.state] ] + sxpr_src = ['src', ['host', self.src_host], ['domain', self.src_dom] ] + sxpr.append(sxpr_src) + sxpr_dst = ['dst', ['host', self.dst] ] + if self.dst_dom: + sxpr_dst.append(['domain', self.dst_dom]) + sxpr.append(sxpr_dst) + return sxpr + + +class XendMigrate: + # Represents migration in progress. + # Use log for indications of begin/end/errors? + # Need logging of: domain create/halt, migrate begin/end/fail + # Log via event server? + + dbpath = "migrate" + + def __init__(self): + self.db = XendDB.XendDB(self.dbpath) + self.migrate = {} + self.migrate_db = self.db.fetchall("") + self.id = 0 + + def nextid(self): + self.id += 1 + return "%d" % self.id + + def sync(self): + self.db.saveall("", self.migrate_db) + + def sync_migrate(self, id): + self.db.save(id, self.migrate_db[id]) + + def close(self): + pass + + def _add_migrate(self, id, info): + self.migrate[id] = info + self.migrate_db[id] = info.sxpr() + self.sync_migrate(id) + #eserver.inject('xend.migrate.begin', info.sxpr()) + + def _delete_migrate(self, id): + #eserver.inject('xend.migrate.end', id) + del self.migrate[id] + del self.migrate_db[id] + self.db.delete(id) + + def migrate_ls(self): + return self.migrate.keys() + + def migrates(self): + return self.migrate.values() + + def migrate_get(self, id): + return self.migrate.get(id) + + def migrate_begin(self, dom, dst): + # Check dom for existence, not migrating already. + # Create migrate info, tell xend to migrate it? + # - or fork migrate command ourselves? + # Subscribe to migrate notifications (for updating). + id = self.nextid() + info = XenMigrateInfo(id, dom, dst) + self._add_migrate(id, info) + return id + +def instance(): + global inst + try: + inst + except: + inst = XendMigrate() + return inst diff --git a/tools/python/xen/xend/XendNode.py b/tools/python/xen/xend/XendNode.py new file mode 100644 index 0000000000..7221785aff --- /dev/null +++ b/tools/python/xen/xend/XendNode.py @@ -0,0 +1,71 @@ +# Copyright (C) 2004 Mike Wray + +"""Handler for node operations. + Has some persistent state: + - logs + - notification urls + +""" + +import os +import xen.ext.xc + +class XendNode: + + def __init__(self): + self.xc = xen.ext.xc.new() + + def shutdown(self): + return 0 + + def reboot(self): + return 0 + + def notify(self, uri): + return 0 + + def cpu_bvt_slice_set(self, slice): + ret = 0 + #ret = self.xc.bvtsched_global_set(ctx_allow=slice) + return ret + + def cpu_bvt_slice_get(self, slice): + ret = 0 + #ret = self.xc.bvtsched_global_get() + return ret + + def cpu_rrobin_slice_set(self, slice): + ret = 0 + #ret = self.xc.rrobin_global_set(slice) + return ret + + def info(self): + return self.nodeinfo() + self.physinfo() + + def nodeinfo(self): + (sys, host, rel, ver, mch) = os.uname() + return [['system', sys], + ['host', host], + ['release', rel], + ['version', ver], + ['machine', mch]] + + def physinfo(self): + pinfo = self.xc.physinfo() + info = [['cores', pinfo['cores']], + ['hyperthreads_per_core', pinfo['ht_per_core']], + ['cpu_mhz', pinfo['cpu_khz']/1000], + ['memory', pinfo['total_pages']/256], + ['free_memory', pinfo['free_pages']/256]] + return info + + + +def instance(): + global inst + try: + inst + except: + inst = XendNode() + return inst + diff --git a/tools/python/xen/xend/XendRoot.py b/tools/python/xen/xend/XendRoot.py new file mode 100644 index 0000000000..665f5df29e --- /dev/null +++ b/tools/python/xen/xend/XendRoot.py @@ -0,0 +1,156 @@ +# Copyright (C) 2004 Mike Wray + +"""Xend root class. +Creates the event server and handles configuration. +""" + +import os +import os.path +import sys +import EventServer + +# Initial create of the event server. +eserver = EventServer.instance() + +import sxp + +def reboots(): + """Get a list of system reboots from wtmp. + """ + out = os.popen('/usr/bin/last reboot', 'r') + list = [ x.strip() for x in out if x.startswith('reboot') ] + return list + +def last_reboot(): + """Get the last known system reboot. + """ + l = reboots() + return (l and l[-1]) or None + +class XendRoot: + """Root of the management classes.""" + + lastboot_default = "/var/xen/lastboot" + + """Default path to the root of the database.""" + dbroot_default = "/var/xen/xend-db" + + """Default path to the config file.""" + config_default = "/etc/xen/xend-config.sxp" + + """Environment variable used to override config_default.""" + config_var = "XEND_CONFIG" + + def __init__(self): + self.rebooted = 0 + self.last_reboot = None + self.dbroot = None + self.config_path = None + self.config = None + self.configure() + self.check_lastboot() + eserver.subscribe('xend.*', self.event_handler) + #eserver.subscribe('xend.domain.created', self.event_handler) + #eserver.subscribe('xend.domain.died', self.event_handler) + + def start(self): + eserver.inject('xend.start', self.rebooted) + + def event_handler(self, event, val): + print >> sys.stderr, "EVENT>", event, val + + def read_lastboot(self): + try: + val = file(self.lastboot, 'rb').readlines()[0] + except StandardError, ex: + print 'warning: Error reading', self.lastboot, ex + val = None + return val + + def write_lastboot(self, val): + if not val: return + try: + fdir = os.path.dirname(self.lastboot) + if not os.path.isdir(fdir): + os.makedirs(fdir) + out = file(self.lastboot, 'wb+') + out.write(val) + out.close() + except IOError, ex: + print 'warning: Error writing', self.lastboot, ex + pass + + def check_lastboot(self): + """Check if there has been a system reboot since we saved lastboot. + """ + last_val = self.read_lastboot() + this_val = last_reboot() + if this_val == last_val: + self.rebooted = 0 + else: + self.rebooted = 1 + self.write_lastboot(this_val) + self.last_reboot = this_val + + def get_last_reboot(self): + return self.last_reboot + + def get_rebooted(self): + return self.rebooted + + def configure(self): + self.set_config() + self.dbroot = self.get_config_value("dbroot", self.dbroot_default) + self.lastboot = self.get_config_value("lastboot", self.lastboot_default) + + def get_dbroot(self): + """Get the path to the database root. + """ + return self.dbroot + + def set_config(self): + """If the config file exists, read it. If not, ignore it. + + The config file is a sequence of sxp forms. + """ + self.config_path = os.getenv(self.config_var, self.config_default) + if os.path.exists(self.config_path): + fin = file(self.config_path, 'rb') + try: + config = sxp.parse(fin) + config.insert(0, 'config') + self.config = config + finally: + fin.close() + else: + self.config = ['config'] + + def get_config(self, name=None): + """Get the configuration element with the given name, or + the whole configuration if no name is given. + + name element name (optional) + returns config or none + """ + if name is None: + val = self.config + else: + val = sxp.child(self.config, name) + return val + + def get_config_value(self, name, val=None): + """Get the value of an atomic configuration element. + + name element name + val default value (optional, defaults to None) + returns value + """ + return sxp.child_value(self.config, name, val=val) + +def instance(): + global inst + try: + inst + except: + inst = XendRoot() + return inst diff --git a/tools/python/xen/xend/XendVnet.py b/tools/python/xen/xend/XendVnet.py new file mode 100644 index 0000000000..213408e111 --- /dev/null +++ b/tools/python/xen/xend/XendVnet.py @@ -0,0 +1,69 @@ +# Copyright (C) 2004 Mike Wray + +"""Handler for vnet operations. +""" + +import sxp +import XendDB + +class XendVnet: + """Index of all vnets. Singleton. + """ + + dbpath = "vnet" + + def __init__(self): + # Table of vnet info indexed by vnet id. + self.vnet = {} + self.db = XendDB.XendDB(self.dbpath) + self.vnet = self.db.fetchall("") + + def vnet_ls(self): + """List all vnets. + """ + return self.vnet.keys() + + def vnets(self): + return self.vnet.values() + + def vnet_get(self, id): + """Get a vnet. + + id vnet id + """ + return self.vnet.get(id) + + def vnet_create(self, info): + """Create a vnet. + + info config + """ + self.vnet_configure(info) + + def vnet_configure(self, info): + """Configure a vnet. + id vnet id + info config + """ + # Need to configure for real. + # Only sync if succeeded - otherwise need to back out. + self.vnet[info.id] = info + self.db.save(info.id, info) + + def vnet_delete(self, id): + """Delete a vnet. + + id vnet id + """ + # Need to delete for real. What if fails? + if id in self.vnet: + del self.vnet[id] + self.db.delete(id) + +def instance(): + global inst + try: + inst + except: + inst = XendVnet() + return inst diff --git a/tools/python/xen/xend/__init__.py b/tools/python/xen/xend/__init__.py new file mode 100644 index 0000000000..8d1c8b69c3 --- /dev/null +++ b/tools/python/xen/xend/__init__.py @@ -0,0 +1 @@ + diff --git a/tools/python/xen/xend/encode.py b/tools/python/xen/xend/encode.py new file mode 100644 index 0000000000..38c9351db7 --- /dev/null +++ b/tools/python/xen/xend/encode.py @@ -0,0 +1,165 @@ +# Copyright (C) 2004 Mike Wray +"""Encoding for arguments to HTTP calls. + Uses the url-encoding with MIME type 'application/x-www-form-urlencoded' + if the data does not include files. Otherwise it uses the encoding with + MIME type 'multipart/form-data'. See the HTML4 spec for details. + + """ +import sys +import types +from StringIO import StringIO + +import urllib +import httplib +import random +import md5 + +# Extract from HTML4 spec. +## The following example illustrates "multipart/form-data" +## encoding. Suppose we have the following form: + +##
+##

+## What is your name?
+## What files are you sending?
+## +##

+ +## If the user enters "Larry" in the text input, and selects the text +## file "file1.txt", the user agent might send back the following data: + +## Content-Type: multipart/form-data; boundary=AaB03x + +## --AaB03x +## Content-Disposition: form-data; name="submit-name" + +## Larry +## --AaB03x +## Content-Disposition: form-data; name="files"; filename="file1.txt" +## Content-Type: text/plain + +## ... contents of file1.txt ... +## --AaB03x-- + +## If the user selected a second (image) file "file2.gif", the user agent +## might construct the parts as follows: + +## Content-Type: multipart/form-data; boundary=AaB03x + +## --AaB03x +## Content-Disposition: form-data; name="submit-name" + +## Larry +## --AaB03x +## Content-Disposition: form-data; name="files" +## Content-Type: multipart/mixed; boundary=BbC04y + +## --BbC04y +## Content-Disposition: file; filename="file1.txt" +## Content-Type: text/plain + +## ... contents of file1.txt ... +## --BbC04y +## Content-Disposition: file; filename="file2.gif" +## Content-Type: image/gif +## Content-Transfer-Encoding: binary + +## ...contents of file2.gif... +## --BbC04y-- +## --AaB03x-- + +__all__ = ['encode_data', 'encode_multipart', 'encode_form', 'mime_boundary' ] + +def data_values(d): + if isinstance(d, types.DictType): + return d.items() + else: + return d + +def encode_data(d): + """Encode some data for HTTP transport. + The encoding used is stored in 'Content-Type' in the headers. + + d data - sequence of tuples or dictionary + returns a 2-tuple of the headers and the encoded data + """ + val = ({}, None) + if d is None: return val + multipart = 0 + for (k, v) in data_values(d): + if encode_isfile(v): + multipart = 1 + break + if multipart: + val = encode_multipart(d) + else: + val = encode_form(d) + return val + +def encode_isfile(v): + if isinstance(v, types.FileType): + return 1 + if hasattr(v, 'readlines'): + return 1 + return 0 + +def encode_multipart(d): + boundary = mime_boundary() + hdr = { 'Content-Type': 'multipart/form-data; boundary=' + boundary } + out = StringIO() + for (k,v) in data_values(d): + out.write('--') + out.write(boundary) + out.write('\r\n') + if encode_isfile(v): + out.write('Content-Disposition: form-data; name="') + out.write(k) + if hasattr(v, 'name'): + out.write('"; filename="') + out.write(v.name) + out.write('"\r\n') + out.write('Content-Type: application/octet-stream\r\n') + out.write('\r\n') + for l in v.readlines(): + out.write(l) + else: + out.write('Content-Disposition: form-data; name="') + out.write(k) + out.write('"\r\n') + out.write('\r\n') + out.write(str(v)) + out.write('\r\n') + out.write('--') + out.write(boundary) + out.write('--') + out.write('\r\n') + return (hdr, out.getvalue()) + +def mime_boundary(): + random.seed() + m = md5.new() + for i in range(0, 10): + c = chr(random.randint(1, 255)) + m.update(c) + b = m.hexdigest() + return b[0:16] + +def encode_form(d): + hdr = { 'Content-Type': 'application/x-www-form-urlencoded' } + val = urllib.urlencode(d) + return (hdr, val) + +def main(): + #d = {'a': 1, 'b': 'x y', 'c': file('conf.sxp') } + #d = {'a': 1, 'b': 'x y' } + d = [ ('a', 1), ('b', 'x y'), ('c', file('conf.sxp')) ] + #d = [ ('a', 1), ('b', 'x y')] + v = encode_data(d) + print v[0] + sys.stdout.write(v[1]) + print + +if __name__ == "__main__": + main() diff --git a/tools/python/xen/xend/server/SrvBase.py b/tools/python/xen/xend/server/SrvBase.py new file mode 100644 index 0000000000..bcff1bc3a0 --- /dev/null +++ b/tools/python/xen/xend/server/SrvBase.py @@ -0,0 +1,137 @@ +# Copyright (C) 2004 Mike Wray + +import cgi + +import os +import sys +import types +import StringIO + +from twisted.internet import defer +from twisted.internet import reactor +from twisted.web import error +from twisted.web import resource +from twisted.web import server + +from xen.xend import sxp +from xen.xend import PrettyPrint + +def uri_pathlist(p): + """Split a path into a list. + p path + return list of path elements + """ + l = [] + for x in p.split('/'): + if x == '': continue + l.append(x) + return l + +class SrvBase(resource.Resource): + """Base class for services. + """ + + def parse_form(self, req, method): + """Parse the data for a request, GET using the URL, POST using encoded data. + Posts should use enctype='multipart/form-data' in the
tag, + rather than 'application/x-www-form-urlencoded'. Only 'multipart/form-data' + handles file upload. + + req request + returns a cgi.FieldStorage instance + """ + env = {} + env['REQUEST_METHOD'] = method + if self.query: + env['QUERY_STRING'] = self.query + val = cgi.FieldStorage(fp=req.rfile, headers=req.headers, environ=env) + return val + + def use_sxp(self, req): + """Determine whether to send an SXP response to a request. + Uses SXP if there is no User-Agent, no Accept, or application/sxp is in Accept. + + req request + returns 1 for SXP, 0 otherwise + """ + ok = 0 + user_agent = req.getHeader('User-Agent') + accept = req.getHeader('Accept') + if (not user_agent) or (not accept) or (accept.find(sxp.mime_type) >= 0): + ok = 1 + return ok + + def get_op_method(self, op): + """Get the method for an operation. + For operation 'foo' looks for 'op_foo'. + + op operation name + returns method or None + """ + op_method_name = 'op_' + op + return getattr(self, op_method_name, None) + + def perform(self, req): + """General operation handler for posted operations. + For operation 'foo' looks for a method op_foo and calls + it with op_foo(op, req). Replies with code 500 if op_foo + is not found. + + The method must return a list when req.use_sxp is true + and an HTML string otherwise (or list). + Methods may also return a Deferred (for incomplete processing). + + req request + """ + op = req.args.get('op') + if op is None or len(op) != 1: + req.setResponseCode(404, "Invalid") + return '' + op = op[0] + op_method = self.get_op_method(op) + if op_method is None: + req.setResponseCode(501, "Not implemented") + req.setHeader("Content-Type", "text/plain") + req.write("Not implemented: " + op) + return '' + else: + val = op_method(op, req) + if isinstance(val, defer.Deferred): + val.addCallback(self._cb_perform, req, 1) + return server.NOT_DONE_YET + else: + self._cb_perform(val, req, 0) + return '' + + def _cb_perform(self, val, req, dfr): + """Callback to complete the request. + May be called from a Deferred. + """ + if isinstance(val, error.ErrorPage): + req.write(val.render(req)) + elif self.use_sxp(req): + req.setHeader("Content-Type", sxp.mime_type) + sxp.show(val, req) + else: + req.write('') + self.print_path(req) + if isinstance(val, types.ListType): + req.write('
')
+                PrettyPrint.prettyprint(val, out=req)
+                req.write('
') + else: + req.write(str(val)) + req.write('') + if dfr: + req.finish() + + def print_path(self, req): + """Print the path with hyperlinks. + """ + pathlist = [x for x in req.prepath if x != '' ] + s = "/" + req.write('

/') + for x in pathlist: + s += x + "/" + req.write(' %s/' % (s, x)) + req.write("

") diff --git a/tools/python/xen/xend/server/SrvConsole.py b/tools/python/xen/xend/server/SrvConsole.py new file mode 100644 index 0000000000..59d0e5f11c --- /dev/null +++ b/tools/python/xen/xend/server/SrvConsole.py @@ -0,0 +1,42 @@ +# Copyright (C) 2004 Mike Wray + +from xen.xend import sxp +from xen.xend import XendConsole +from SrvDir import SrvDir + +class SrvConsole(SrvDir): + """An individual console. + """ + + def __init__(self, info): + SrvDir.__init__(self) + self.info = info + self.xc = XendConsole.instance() + + def op_disconnect(self, op, req): + val = self.xc.console_disconnect(self.info.id) + return val + + def render_POST(self, req): + return self.perform(req) + + def render_GET(self, req): + if self.use_sxp(req): + req.setHeader("Content-Type", sxp.mime_type) + sxp.show(self.info.sxpr(), out=req) + else: + req.write('') + self.print_path(req) + #self.ls() + req.write('

%s

' % self.info) + req.write('

Connect to domain %d

' + % (self.info.uri(), self.info.dom2)) + self.form(req) + req.write('') + return '' + + def form(self, req): + req.write('' % req.prePathURL()) + if self.info.connection(): + req.write('') + req.write('') diff --git a/tools/python/xen/xend/server/SrvConsoleDir.py b/tools/python/xen/xend/server/SrvConsoleDir.py new file mode 100644 index 0000000000..814b448370 --- /dev/null +++ b/tools/python/xen/xend/server/SrvConsoleDir.py @@ -0,0 +1,59 @@ +# Copyright (C) 2004 Mike Wray + +from SrvDir import SrvDir +from SrvConsole import SrvConsole +from xen.xend import XendConsole +from xen.xend import sxp + +class SrvConsoleDir(SrvDir): + """Console directory. + """ + + def __init__(self): + SrvDir.__init__(self) + self.xconsole = XendConsole.instance() + + def console(self, x): + val = None + try: + info = self.xconsole.console_get(x) + val = SrvConsole(info) + except KeyError, ex: + print 'SrvConsoleDir>', ex + pass + return val + + def get(self, x): + v = SrvDir.get(self, x) + if v is not None: + return v + v = self.console(x) + return v + + def render_GET(self, req): + if self.use_sxp(req): + req.setHeader("Content-Type", sxp.mime_type) + self.ls_console(req, 1) + else: + req.write("") + self.print_path(req) + self.ls(req) + self.ls_console(req) + #self.form(req.wfile) + req.write("") + return '' + + def ls_console(self, req, use_sxp=0): + url = req.prePathURL() + if not url.endswith('/'): + url += '/' + if use_sxp: + consoles = self.xconsole.console_ls() + sxp.show(consoles, out=req) + else: + consoles = self.xconsole.consoles() + consoles.sort(lambda x, y: cmp(x.id, y.id)) + req.write('
    ') + for c in consoles: + req.write('
  • %s
  • ' % (url, c.id, c)) + req.write('
') diff --git a/tools/python/xen/xend/server/SrvDaemon.py b/tools/python/xen/xend/server/SrvDaemon.py new file mode 100644 index 0000000000..c8284dc485 --- /dev/null +++ b/tools/python/xen/xend/server/SrvDaemon.py @@ -0,0 +1,751 @@ +########################################################### +## Xen controller daemon +## Copyright (c) 2004, K A Fraser (University of Cambridge) +## Copyright (C) 2004, Mike Wray +########################################################### + +import os +import os.path +import signal +import sys +import threading +import linecache +import socket +import pwd +import re +import StringIO + +from twisted.internet import pollreactor +pollreactor.install() + +from twisted.internet import reactor +from twisted.internet import protocol +from twisted.internet import abstract +from twisted.internet import defer + +from xen.ext import xu + +from xen.xend import sxp +from xen.xend import PrettyPrint +from xen.xend import EventServer +eserver = EventServer.instance() + +from xen.xend.server import SrvServer + +import channel +import blkif +import netif +import console +import domain +from params import * + +DEBUG = 1 + +class MgmtProtocol(protocol.DatagramProtocol): + """Handler for the management socket (unix-domain). + """ + + def __init__(self, daemon): + #protocol.DatagramProtocol.__init__(self) + self.daemon = daemon + + def write(self, data, addr): + return self.transport.write(data, addr) + + def datagramReceived(self, data, addr): + if DEBUG: print 'datagramReceived> addr=', addr, 'data=', data + io = StringIO.StringIO(data) + try: + vals = sxp.parse(io) + res = self.dispatch(vals[0]) + self.send_result(addr, res) + except SystemExit: + raise + except: + if DEBUG: + raise + else: + self.send_error(addr) + + def send_reply(self, addr, sxpr): + io = StringIO.StringIO() + sxp.show(sxpr, out=io) + io.seek(0) + self.write(io.getvalue(), addr) + + def send_result(self, addr, res): + + def fn(res, self=self, addr=addr): + self.send_reply(addr, ['ok', res]) + + if isinstance(res, defer.Deferred): + res.addCallback(fn) + else: + fn(res) + + def send_error(self, addr): + (extype, exval) = sys.exc_info()[:2] + self.send_reply(addr, ['err', + ['type', str(extype) ], + ['value', str(exval) ] ] ) + + def opname(self, name): + """Get the name of the method for an operation. + """ + return 'op_' + name.replace('.', '_') + + def operror(self, name, v): + """Default operation handler - signals an error. + """ + raise NotImplementedError('Invalid operation: ' +name) + + def dispatch(self, req): + """Dispatch a request to its handler. + """ + op_name = sxp.name(req) + op_method_name = self.opname(op_name) + op_method = getattr(self, op_method_name, self.operror) + return op_method(op_name, req) + + def op_console_create(self, name, req): + """Create a new control interface - console for a domain. + """ + print name, req + dom = sxp.child_value(req, 'domain') + if not dom: raise ValueError('Missing domain') + dom = int(dom) + console_port = sxp.child_value(req, 'console_port') + if console_port: + console_port = int(console_port) + resp = self.daemon.console_create(dom, console_port) + print name, resp + return resp + + def op_consoles(self, name, req): + """Get a list of the consoles. + """ + return self.daemon.consoles() + + def op_console_disconnect(self, name, req): + id = sxp.child_value(req, 'id') + if not id: + raise ValueError('Missing console id') + id = int(id) + console = self.daemon.get_console(id) + if not console: + raise ValueError('Invalid console id') + if console.conn: + console.conn.loseConnection() + return ['ok'] + + def op_blkifs(self, name, req): + pass + + def op_blkif_devs(self, name, req): + pass + + def op_blkif_create(self, name, req): + pass + + def op_blkif_dev_create(self, name, req): + pass + + def op_netifs(self, name, req): + pass + + def op_netif_devs(self, name, req): + pass + + def op_netif_create(self, name, req): + pass + + def op_netif_dev_create(self, name, req): + pass + +class NotifierProtocol(protocol.Protocol): + """Asynchronous handler for i/o on the notifier (event channel). + """ + + def __init__(self, channelFactory): + self.channelFactory = channelFactory + + def notificationReceived(self, idx, type): + #print 'NotifierProtocol>notificationReceived>', idx, type + channel = self.channelFactory.getChannel(idx) + if not channel: + return + #print 'NotifierProtocol>notificationReceived> channel', channel + channel.notificationReceived(type) + + def connectionLost(self, reason=None): + pass + + def doStart(self): + pass + + def doStop(self): + pass + + def startProtocol(self): + pass + + def stopProtocol(self): + pass + +class NotifierPort(abstract.FileDescriptor): + """Transport class for the event channel. + """ + + def __init__(self, daemon, notifier, proto, reactor=None): + assert isinstance(proto, NotifierProtocol) + abstract.FileDescriptor.__init__(self, reactor) + self.daemon = daemon + self.notifier = notifier + self.protocol = proto + + def startListening(self): + self._bindNotifier() + self._connectToProtocol() + + def stopListening(self): + if self.connected: + result = self.d = defer.Deferred() + else: + result = None + self.loseConnection() + return result + + def fileno(self): + return self.notifier.fileno() + + def _bindNotifier(self): + self.connected = 1 + + def _connectToProtocol(self): + self.protocol.makeConnection(self) + self.startReading() + + def loseConnection(self): + if self.connected: + self.stopReading() + self.disconnecting = 1 + reactor.callLater(0, self.connectionLost) + + def connectionLost(self, reason=None): + abstract.FileDescriptor.connectionLost(self, reason) + if hasattr(self, 'protocol'): + self.protocol.doStop() + self.connected = 0 + #self.notifier.close() # Not implemented. + os.close(self.fileno()) + del self.notifier + if hasattr(self, 'd'): + self.d.callback(None) + del self.d + + def doRead(self): + #print 'NotifierPort>doRead>', self + count = 0 + while 1: + #print 'NotifierPort>doRead>', count + notification = self.notifier.read() + if not notification: + break + (idx, type) = notification + self.protocol.notificationReceived(idx, type) + self.notifier.unmask(idx) + count += 1 + #print 'NotifierPort>doRead<' + +class EventProtocol(protocol.Protocol): + """Asynchronous handler for a connected event socket. + """ + + def __init__(self, daemon): + #protocol.Protocol.__init__(self) + self.daemon = daemon + # Event queue. + self.queue = [] + # Subscribed events. + self.events = [] + self.parser = sxp.Parser() + self.pretty = 0 + + # For debugging subscribe to everything and make output pretty. + self.subscribe(['*']) + self.pretty = 1 + + def dataReceived(self, data): + try: + self.parser.input(data) + if self.parser.ready(): + val = self.parser.get_val() + res = self.dispatch(val) + self.send_result(res) + if self.parser.at_eof(): + self.loseConnection() + except SystemExit: + raise + except: + if DEBUG: + raise + else: + self.send_error() + + def loseConnection(self): + if self.transport: + self.transport.loseConnection() + if self.connected: + reactor.callLater(0, self.connectionLost) + + def connectionLost(self, reason=None): + self.unsubscribe() + + def send_reply(self, sxpr): + io = StringIO.StringIO() + if self.pretty: + PrettyPrint.prettyprint(sxpr, out=io) + else: + sxp.show(sxpr, out=io) + print >> io + io.seek(0) + return self.transport.write(io.getvalue()) + + def send_result(self, res): + return self.send_reply(['ok', res]) + + def send_error(self): + (extype, exval) = sys.exc_info()[:2] + return self.send_reply(['err', + ['type', str(extype)], + ['value', str(exval)]]) + + def send_event(self, val): + return self.send_reply(['event', val[0], val[1]]) + + def unsubscribe(self): + for event in self.events: + eserver.unsubscribe(event, self.queue_event) + + def subscribe(self, events): + self.unsubscribe() + for event in events: + eserver.subscribe(event, self.queue_event) + self.events = events + + def queue_event(self, name, v): + # Despite the name we dont' queue the event here. + # We send it because the transport will queue it. + self.send_event([name, v]) + + def opname(self, name): + return 'op_' + name.replace('.', '_') + + def operror(self, name, req): + raise NotImplementedError('Invalid operation: ' +name) + + def dispatch(self, req): + op_name = sxp.name(req) + op_method_name = self.opname(op_name) + op_method = getattr(self, op_method_name, self.operror) + return op_method(op_name, req) + + def op_help(self, name, req): + def nameop(x): + if x.startswith('op_'): + return x[3:].replace('_', '.') + else: + return x + + l = [ nameop(k) for k in dir(self) if k.startswith('op_') ] + return l + + def op_quit(self, name, req): + self.loseConnection() + + def op_exit(self, name, req): + sys.exit(0) + + def op_pretty(self, name, req): + self.pretty = 1 + return ['ok'] + + def op_console_disconnect(self, name, req): + id = sxp.child_value(req, 'id') + if not id: + raise ValueError('Missing console id') + self.daemon.console_disconnect(id) + return ['ok'] + + def op_info(self, name, req): + val = ['info'] + val += self.daemon.consoles() + val += self.daemon.blkifs() + val += self.daemon.netifs() + return val + + def op_sys_subscribe(self, name, v): + # (sys.subscribe event*) + # Subscribe to the events: + self.subscribe(v[1:]) + return ['ok'] + + def op_sys_inject(self, name, v): + # (sys.inject event) + event = v[1] + eserver.inject(sxp.name(event), event) + return ['ok'] + + +class EventFactory(protocol.Factory): + """Asynchronous handler for the event server socket. + """ + protocol = EventProtocol + service = None + + def __init__(self, daemon): + #protocol.Factory.__init__(self) + self.daemon = daemon + + def buildProtocol(self, addr): + proto = self.protocol(self.daemon) + proto.factory = self + return proto + +class VirqClient: + def __init__(self, daemon): + self.daemon = daemon + + def virqReceived(self, virq): + print 'VirqClient.virqReceived>', virq + eserver.inject('xend.virq', virq) + + def lostChannel(self, channel): + print 'VirqClient.lostChannel>', channel + +class Daemon: + """The xend daemon. + """ + def __init__(self): + self.shutdown = 0 + + def daemon_pids(self): + pids = [] + pidex = '(?P\d+)' + pythonex = '(?P\S*python\S*)' + cmdex = '(?P.*)' + procre = re.compile('^\s*' + pidex + '\s*' + pythonex + '\s*' + cmdex + '$') + xendre = re.compile('^/usr/sbin/xend\s*(start|restart)\s*.*$') + procs = os.popen('ps -e -o pid,args 2>/dev/null') + for proc in procs: + pm = procre.match(proc) + if not pm: continue + xm = xendre.match(pm.group('cmd')) + if not xm: continue + #print 'pid=', pm.group('pid'), 'cmd=', pm.group('cmd') + pids.append(int(pm.group('pid'))) + return pids + + def new_cleanup(self, kill=0): + err = 0 + pids = self.daemon_pids() + if kill: + for pid in pids: + print "Killing daemon pid=%d" % pid + os.kill(pid, signal.SIGHUP) + elif pids: + err = 1 + print "Daemon already running: ", pids + return err + + def cleanup(self, kill=False): + # No cleanup to do if PID_FILE is empty. + if not os.path.isfile(PID_FILE) or not os.path.getsize(PID_FILE): + return 0 + # Read the pid of the previous invocation and search active process list. + pid = open(PID_FILE, 'r').read() + lines = os.popen('ps ' + pid + ' 2>/dev/null').readlines() + for line in lines: + if re.search('^ *' + pid + '.+xend', line): + if not kill: + print "Daemon is already running (pid %d)" % int(pid) + return 1 + # Old daemon is still active: terminate it. + os.kill(int(pid), 1) + # Delete the stale PID_FILE. + os.remove(PID_FILE) + return 0 + + def install_child_reaper(self): + #signal.signal(signal.SIGCHLD, self.onSIGCHLD) + # Ensure that zombie children are automatically reaped. + xu.autoreap() + + def onSIGCHLD(self, signum, frame): + code = 1 + while code > 0: + code = os.waitpid(-1, os.WNOHANG) + + def start(self,trace=0): + if self.cleanup(kill=False): + return 1 + + # Detach from TTY. + if not DEBUG: + os.setsid() + + if self.set_user(): + return 1 + + self.install_child_reaper() + + # Fork -- parent writes PID_FILE and exits. + pid = os.fork() + if pid: + # Parent + pidfile = open(PID_FILE, 'w') + pidfile.write(str(pid)) + pidfile.close() + return 0 + # Child + logfile = self.open_logfile() + self.redirect_output(logfile) + if trace: + self.tracefile = open('/var/log/xend.trace', 'w+', 1) + self.traceindent = 0 + sys.settrace(self.trace) + try: + threading.settrace(self.trace) # Only in Python >= 2.3 + except: + pass + self.run() + return 0 + + def print_trace(self,str): + for i in range(self.traceindent): + self.tracefile.write(" ") + self.tracefile.write(str) + + def trace(self, frame, event, arg): + if event == 'call': + code = frame.f_code + filename = code.co_filename + m = re.search('.*xenmgr/(.*)', code.co_filename) + if not m: + return None + modulename = m.group(1) + if re.search('sxp.py', modulename): + return None + self.traceindent += 1 + self.print_trace("++++ %s:%s\n" + % (modulename, code.co_name)) + elif event == 'line': + filename = frame.f_code.co_filename + lineno = frame.f_lineno + self.print_trace("%4d %s" % + (lineno, linecache.getline(filename, lineno))) + elif event == 'return': + code = frame.f_code + filename = code.co_filename + m = re.search('.*xenmgr/(.*)', code.co_filename) + if not m: + return None + modulename = m.group(1) + self.print_trace("---- %s:%s\n" + % (modulename, code.co_name)) + self.traceindent -= 1 + elif event == 'exception': + pass + return self.trace + + def open_logfile(self): + if not os.path.exists(CONTROL_DIR): + os.makedirs(CONTROL_DIR) + + # Open log file. Truncate it if non-empty, and request line buffering. + if os.path.isfile(LOG_FILE): + os.rename(LOG_FILE, LOG_FILE+'.old') + logfile = open(LOG_FILE, 'w+', 1) + return logfile + + def set_user(self): + # Set the UID. + try: + os.setuid(pwd.getpwnam(USER)[2]) + return 0 + except KeyError, error: + print "Error: no such user '%s'" % USER + return 1 + + def redirect_output(self, logfile): + if DEBUG: return + # Close down standard file handles + try: + os.close(0) # stdin + os.close(1) # stdout + os.close(2) # stderr + except: + pass + # Redirect output to log file. + sys.stdout = sys.stderr = logfile + + def stop(self): + return self.cleanup(kill=True) + + def run(self): + self.createFactories() + self.listenMgmt() + self.listenEvent() + self.listenNotifier() + self.listenVirq() + SrvServer.create(bridge=1) + reactor.run() + + def createFactories(self): + self.channelF = channel.channelFactory() + self.domainCF = domain.DomainControllerFactory() + self.blkifCF = blkif.BlkifControllerFactory() + self.netifCF = netif.NetifControllerFactory() + self.consoleCF = console.ConsoleControllerFactory() + + def listenMgmt(self): + protocol = MgmtProtocol(self) + s = os.path.join(CONTROL_DIR, MGMT_SOCK) + if os.path.exists(s): + os.unlink(s) + return reactor.listenUNIXDatagram(s, protocol) + + def listenEvent(self): + protocol = EventFactory(self) + return reactor.listenTCP(EVENT_PORT, protocol) + + def listenNotifier(self): + protocol = NotifierProtocol(self.channelF) + p = NotifierPort(self, self.channelF.notifier, protocol, reactor) + p.startListening() + return p + + def listenVirq(self): + virqChan = self.channelF.virqChannel(channel.VIRQ_DOM_EXC) + virqChan.registerClient(VirqClient(self)) + + def exit(self): + reactor.diconnectAll() + sys.exit(0) + + def blkif_set_control_domain(self, dom, recreate=0): + """Set the block device backend control domain. + """ + return self.blkifCF.setControlDomain(dom, recreate=recreate) + + def blkif_get_control_domain(self, dom): + """Get the block device backend control domain. + """ + return self.blkifCF.getControlDomain() + + def blkif_create(self, dom, recreate=0): + """Create a block device interface controller. + + Returns Deferred + """ + d = self.blkifCF.createInstance(dom, recreate=recreate) + return d + + def blkifs(self): + return [ x.sxpr() for x in self.blkifCF.getInstances() ] + + def blkif_get(self, dom): + return self.blkifCF.getInstanceByDom(dom) + + def blkif_dev(self, dom, vdev): + return self.blkifCF.getDomainDevice(dom, vdev) + + def blkif_dev_create(self, dom, vdev, mode, segment, recreate=0): + """Create a block device. + + Returns Deferred + """ + ctrl = self.blkifCF.getInstanceByDom(dom) + if not ctrl: + raise ValueError('No blkif controller: %d' % dom) + print 'blkif_dev_create>', dom, vdev, mode, segment + d = ctrl.attachDevice(vdev, mode, segment, recreate=recreate) + return d + + def netif_set_control_domain(self, dom, recreate=0): + """Set the network interface backend control domain. + """ + return self.netifCF.setControlDomain(dom, recreate=recreate) + + def netif_get_control_domain(self, dom): + """Get the network interface backend control domain. + """ + return self.netifCF.getControlDomain() + + def netif_create(self, dom, recreate=0): + """Create a network interface controller. + + """ + return self.netifCF.createInstance(dom, recreate=recreate) + + def netifs(self): + return [ x.sxpr() for x in self.netifCF.getInstances() ] + + def netif_get(self, dom): + return self.netifCF.getInstanceByDom(dom) + + def netif_dev_create(self, dom, vif, vmac, recreate=0): + """Create a network device. + + todo + """ + ctrl = self.netifCF.getInstanceByDom(dom) + if not ctrl: + raise ValueError('No netif controller: %d' % dom) + d = ctrl.attachDevice(vif, vmac, recreate=recreate) + return d + + def netif_dev(self, dom, vif): + return self.netifCF.getDomainDevice(dom, vif) + + def console_create(self, dom, console_port=None): + """Create a console for a domain. + """ + console = self.consoleCF.getInstanceByDom(dom) + if console is None: + console = self.consoleCF.createInstance(dom, console_port) + return console.sxpr() + + def consoles(self): + return [ c.sxpr() for c in self.consoleCF.getInstances() ] + + def get_console(self, id): + return self.consoleCF.getInstance(id) + + def get_domain_console(self, dom): + return self.consoleCF.getInstanceByDom(dom) + + def console_disconnect(self, id): + """Disconnect any connected console client. + """ + console = self.get_console(id) + if not console: + raise ValueError('Invalid console id') + console.disconnect() + + def domain_shutdown(self, dom, reason): + """Shutdown a domain. + """ + ctrl = self.domainCF.getInstanceByDom(dom) + if not ctrl: + raise ValueError('No domain controller: %d' % dom) + ctrl.shutdown(reason) + return 0 + +def instance(): + global inst + try: + inst + except: + inst = Daemon() + return inst diff --git a/tools/python/xen/xend/server/SrvDeviceDir.py b/tools/python/xen/xend/server/SrvDeviceDir.py new file mode 100644 index 0000000000..52f428540d --- /dev/null +++ b/tools/python/xen/xend/server/SrvDeviceDir.py @@ -0,0 +1,9 @@ +# Copyright (C) 2004 Mike Wray + +from SrvDir import SrvDir + +class SrvDeviceDir(SrvDir): + """Device directory. + """ + + pass diff --git a/tools/python/xen/xend/server/SrvDir.py b/tools/python/xen/xend/server/SrvDir.py new file mode 100644 index 0000000000..c49c0b36ba --- /dev/null +++ b/tools/python/xen/xend/server/SrvDir.py @@ -0,0 +1,91 @@ +# Copyright (C) 2004 Mike Wray + +from twisted.web import error +from xen.xend import sxp +from SrvBase import SrvBase + +class SrvConstructor: + """Delayed constructor for sub-servers. + Does not import the sub-server class or create the object until needed. + """ + + def __init__(self, klass): + """Create a constructor. It is assumed that the class + should be imported as 'import klass from klass'. + + klass name of its class + """ + self.klass = klass + self.obj = None + + def getobj(self): + """Get the sub-server object, importing its class and instantiating it if + necessary. + """ + if not self.obj: + exec 'from %s import %s' % (self.klass, self.klass) + klassobj = eval(self.klass) + self.obj = klassobj() + return self.obj + +class SrvDir(SrvBase): + """Base class for directory servlets. + """ + isLeaf = False + + def __init__(self): + SrvBase.__init__(self) + self.table = {} + self.order = [] + + def getChild(self, x, req): + if x == '': return self + val = self.get(x) + if val is None: + return error.NoResource('Not found') + else: + return val + + def get(self, x): + val = self.table.get(x) + if val is not None: + val = val.getobj() + return val + + def add(self, x, xclass = None): + if xclass is None: + xclass = 'SrvDir' + self.table[x] = SrvConstructor(xclass) + self.order.append(x) + + def render_GET(self, req): + if self.use_sxp(req): + req.setHeader("Content-type", sxp.mime_type) + self.ls(req, 1) + else: + req.write('') + self.print_path(req) + self.ls(req) + self.form(req) + req.write('') + return '' + + def ls(self, req, use_sxp=0): + url = req.prePathURL() + if not url.endswith('/'): + url += '/' + if use_sxp: + req.write('(ls ') + for k in self.order: + req.write(' ' + k) + req.write(')') + else: + req.write('
    ') + for k in self.order: + v = self.get(k) + req.write('
  • %s
  • ' + % (url, k, k)) + req.write('
') + + def form(self, req): + pass diff --git a/tools/python/xen/xend/server/SrvDomain.py b/tools/python/xen/xend/server/SrvDomain.py new file mode 100644 index 0000000000..156198bd70 --- /dev/null +++ b/tools/python/xen/xend/server/SrvDomain.py @@ -0,0 +1,195 @@ +# Copyright (C) 2004 Mike Wray + +from xen.xend import sxp +from xen.xend import XendDomain +from xen.xend import XendConsole +from xen.xend import PrettyPrint +from xen.xend.Args import FormFn + +from SrvDir import SrvDir + +class SrvDomain(SrvDir): + """Service managing a single domain. + """ + + def __init__(self, dom): + SrvDir.__init__(self) + self.dom = dom + self.xd = XendDomain.instance() + self.xconsole = XendConsole.instance() + + def op_unpause(self, op, req): + val = self.xd.domain_unpause(self.dom.id) + return val + + def op_pause(self, op, req): + val = self.xd.domain_pause(self.dom.id) + return val + + def op_shutdown(self, op, req): + val = self.xd.domain_shutdown(self.dom.id) + req.setResponseCode(202) + req.setHeader("Location", "%s/.." % req.prePathURL()) + return val + + def op_destroy(self, op, req): + val = self.xd.domain_destroy(self.dom.id) + req.setHeader("Location", "%s/.." % req.prePathURL()) + return val + + def op_save(self, op, req): + fn = FormFn(self.xd.domain_save, + [['dom', 'int'], + ['file', 'str']]) + val = fn(req.args, {'dom': self.dom.id}) + return val + + def op_migrate(self, op, req): + fn = FormFn(self.xd.domain_migrate, + [['dom', 'int'], + ['destination', 'str']]) + val = fn(req.args, {'dom': self.dom.id}) + val = 0 # Some migrate id. + req.setResponseCode(202) + #req.send_header("Location", "%s/.." % self.path) # Some migrate url. + return val + + def op_pincpu(self, op, req): + fn = FormFn(self.xd.domain_pincpu, + [['dom', 'int'], + ['cpu', 'int']]) + val = fn(req.args, {'dom': self.dom.id}) + return val + + def op_cpu_bvt_set(self, op, req): + fn = FormFn(self.xd.domain_cpu_bvt_set, + [['dom', 'int'], + ['mcuadv', 'int'], + ['warp', 'int'], + ['warpl', 'int'], + ['warpu', 'int']]) + val = fn(req.args, {'dom': self.dom.id}) + return val + + def op_cpu_atropos_set(self, op, req): + fn = FormFn(self.xd.domain_cpu_atropos_set, + [['dom', 'int'], + ['period', 'int'], + ['slice', 'int'], + ['latency', 'int'], + ['xtratime', 'int']]) + val = fn(req.args, {'dom': self.dom.id}) + return val + + def op_vifs(self, op, req): + return self.xd.domain_vif_ls(self.dom.id) + + def op_vif(self, op, req): + fn = FormFn(self.xd.domain_vif_get, + [['dom', 'int'], + ['vif', 'int']]) + val = fn(req.args, {'dom': self.dom.id}) + return val + + def op_vif_stats(self, op, req): + #todo + fn = FormFn(self.xd.domain_vif_stats, + [['dom', 'int'], + ['vif', 'int']]) + #val = fn(req.args, {'dom': self.dom.id}) + val = 999 + #return val + return val + + def op_vif_ip_add(self, op, req): + fn = FormFn(self.xd.domain_vif_ip_add, + [['dom', 'int'], + ['vif', 'int'], + ['ip', 'str']]) + val = fn(req.args, {'dom': self.dom.id}) + return val + + def op_vif_scheduler_set(self, op, req): + fn = FormFn(self.xd.domain_vif_scheduler_set, + [['dom', 'int'], + ['vif', 'int'], + ['bytes', 'int'], + ['usecs', 'int']]) + val = fn(req.args, {'dom': self.dom.id}) + return val + + def op_vif_scheduler_get(self, op, req): + fn = FormFn(self.xd.domain_vif_scheduler_set, + [['dom', 'int'], + ['vif', 'int']]) + val = fn(req.args, {'dom': self.dom.id}) + return val + + def op_vbds(self, op, req): + return self.xd.domain_vbd_ls(self.dom.id) + + def op_vbd(self, op, req): + fn = FormFn(self.xd.domain_vbd_get, + [['dom', 'int'], + ['vbd', 'int']]) + val = fn(req.args, {'dom': self.dom.id}) + return val + + def op_vbd_add(self, op, req): + fn = FormFn(self.xd.domain_vbd_add, + [['dom', 'int'], + ['uname', 'str'], + ['dev', 'str'], + ['mode', 'str']]) + val = fn(req.args, {'dom': self.dom.id}) + return val + + def op_vbd_remove(self, op, req): + fn = FormFn(self.xd.domain_vbd_remove, + [['dom', 'int'], + ['dev', 'str']]) + val = fn(req.args, {'dom': self.dom.id}) + return val + + def render_POST(self, req): + return self.perform(req) + + def render_GET(self, req): + op = req.args.get('op') + if op and op[0] in ['vifs', 'vif', 'vif_stats', 'vbds', 'vbd']: + return self.perform(req) + if self.use_sxp(req): + req.setHeader("Content-Type", sxp.mime_type) + sxp.show(self.dom.sxpr(), out=req) + else: + req.write('') + self.print_path(req) + #self.ls() + req.write('

%s

' % self.dom) + if self.dom.console: + cinfo = self.dom.console + cid = cinfo.id + #todo: Local xref: need to know server prefix. + req.write('

Console %s

' + % (cid, cid)) + req.write('

Connect to console

' + % cinfo.uri()) + if self.dom.config: + req.write("
")
+                PrettyPrint.prettyprint(self.dom.config, out=req)
+                req.write("
") + req.write('vif 0 stats' + % req.prePathURL()) + self.form(req) + req.write('') + return '' + + def form(self, req): + req.write('
' % req.prePathURL()) + req.write('') + req.write('') + req.write('') + req.write('') + req.write('
') + req.write('To: ') + req.write('
') diff --git a/tools/python/xen/xend/server/SrvDomainDir.py b/tools/python/xen/xend/server/SrvDomainDir.py new file mode 100644 index 0000000000..af4bc7a15c --- /dev/null +++ b/tools/python/xen/xend/server/SrvDomainDir.py @@ -0,0 +1,144 @@ +# Copyright (C) 2004 Mike Wray + +from StringIO import StringIO + +from twisted.protocols import http +from twisted.web import error + +from xen.xend import sxp +from xen.xend import XendDomain +from xen.xend.Args import FormFn + +from SrvDir import SrvDir +from SrvDomain import SrvDomain + +class SrvDomainDir(SrvDir): + """Service that manages the domain directory. + """ + + def __init__(self): + SrvDir.__init__(self) + self.xd = XendDomain.instance() + + def domain(self, x): + val = None + try: + dom = self.xd.domain_get(x) + val = SrvDomain(dom) + except KeyError, ex: + print 'SrvDomainDir>', ex + pass + return val + + def get(self, x): + v = SrvDir.get(self, x) + if v is not None: + return v + v = self.domain(x) + return v + + def op_create(self, op, req): + ok = 0 + try: + configstring = req.args.get('config')[0] + print 'config:', configstring + pin = sxp.Parser() + pin.input(configstring) + pin.input_eof() + config = pin.get_val() + ok = 1 + except Exception, ex: + print 'op_create>', ex + if not ok: + req.setResponseCode(http.BAD_REQUEST, "Invalid configuration") + return "Invalid configuration" + return error.ErrorPage(http.BAD_REQUEST, + "Invalid", + "Invalid configuration") + try: + deferred = self.xd.domain_create(config) + deferred.addCallback(self._cb_op_create, configstring, req) + return deferred + except Exception, ex: + raise + #return ['err', str(ex) ] + #req.setResponseCode(http.BAD_REQUEST, "Error creating domain") + #return str(ex) + #return error.ErrorPage(http.BAD_REQUEST, + # "Error creating domain", + # str(ex)) + + + def _cb_op_create(self, dominfo, configstring, req): + """Callback to handle deferred domain creation. + """ + dom = dominfo.id + domurl = "%s/%s" % (req.prePathURL(), dom) + req.setResponseCode(201, "created") + req.setHeader("Location", domurl) + if self.use_sxp(req): + return dominfo.sxpr() + else: + out = StringIO() + print >> out, ('

Created Domain %s

' + % (domurl, dom)) + print >> out, '

'
+            print >> out, configstring
+            print >> out, '

' + val = out.getvalue() + out.close() + return val + + def op_restore(self, op, req): + fn = FormFn(self.xd.domain_restore, + [['file', 'str']]) + val = fn(req.args) + return val + + def render_POST(self, req): + return self.perform(req) + + def render_GET(self, req): + if self.use_sxp(req): + req.setHeader("Content-Type", sxp.mime_type) + self.ls_domain(req, 1) + else: + req.write("") + self.print_path(req) + self.ls(req) + self.ls_domain(req) + self.form(req) + req.write("") + return '' + + def ls_domain(self, req, use_sxp=0): + url = req.prePathURL() + if not url.endswith('/'): + url += '/' + if use_sxp: + domains = self.xd.domain_ls() + sxp.show(domains, out=req) + else: + domains = self.xd.domains() + domains.sort(lambda x, y: cmp(x.id, y.id)) + req.write('
    ') + for d in domains: + req.write('
  • Domain %s' + % (url, d.id, d.id)) + req.write('name=%s' % d.name) + req.write('memory=%d'% d.memory) + req.write('
  • ') + req.write('
') + + def form(self, req): + req.write('
' + % req.prePathURL()) + req.write('') + req.write('Config
') + req.write('
') + req.write('
' + % req.prePathURL()) + req.write('') + req.write('State
') + req.write('
') + diff --git a/tools/python/xen/xend/server/SrvEventDir.py b/tools/python/xen/xend/server/SrvEventDir.py new file mode 100644 index 0000000000..02871a426a --- /dev/null +++ b/tools/python/xen/xend/server/SrvEventDir.py @@ -0,0 +1,41 @@ +# Copyright (C) 2004 Mike Wray + +from xen.xend import sxp +from xen.xend import EventServer +from SrvDir import SrvDir + +class SrvEventDir(SrvDir): + """Event directory. + """ + + def __init__(self): + SrvDir.__init__(self) + self.eserver = EventServer.instance() + + def op_inject(self, op, req): + eventstring = req.args.get('event') + pin = sxp.Parser() + pin.input(eventstring) + pin.input_eof() + sxpr = pin.get_val() + self.eserver.inject(sxp.name(sxpr), sxpr) + if req.use_sxp: + sxp.name(sxpr) + else: + return '' + eventstring + '' + + def render_POST(self, req): + return self.perform(req) + + def form(self, req): + action = req.prePathURL() + req.write('
' + % action) + req.write('') + req.write('Event
') + req.write('
') + req.write('
' + % action) + req.write('') + req.write('Event file
') + req.write('
') diff --git a/tools/python/xen/xend/server/SrvNode.py b/tools/python/xen/xend/server/SrvNode.py new file mode 100644 index 0000000000..69747d80c1 --- /dev/null +++ b/tools/python/xen/xend/server/SrvNode.py @@ -0,0 +1,54 @@ +# Copyright (C) 2004 Mike Wray + +import os +from SrvDir import SrvDir +from xen.xend import sxp +from xen.xend import XendNode + +class SrvNode(SrvDir): + """Information about the node. + """ + + def __init__(self): + SrvDir.__init__(self) + self.xn = XendNode.instance() + + def op_shutdown(self, op, req): + val = self.xn.shutdown() + return val + + def op_reboot(self, op, req): + val = self.xn.reboot() + return val + + def op_cpu_rrobin_slice_set(self, op, req): + fn = FormFn(self.xn.cpu_rrobin_slice_set, + [['slice', 'int']]) + val = fn(req.args, {}) + return val + + def op_cpu_bvt_slice_set(self, op, req): + fn = FormFn(self.xn.cpu_bvt_slice_set, + [['slice', 'int']]) + val = fn(req.args, {}) + return val + + def render_POST(self, req): + return self.perform(req) + + def render_GET(self, req): + if self.use_sxp(req): + req.setHeader("Content-Type", sxp.mime_type) + sxp.show(['node'] + self.info(), out=req) + else: + req.write('') + self.print_path(req) + req.write('
    ') + for d in self.info(): + req.write('
  • %10s: %s' % (d[0], str(d[1]))) + req.write('
') + req.write('') + return '' + + def info(self): + return self.xn.info() diff --git a/tools/python/xen/xend/server/SrvRoot.py b/tools/python/xen/xend/server/SrvRoot.py new file mode 100644 index 0000000000..8d38937b72 --- /dev/null +++ b/tools/python/xen/xend/server/SrvRoot.py @@ -0,0 +1,30 @@ +# Copyright (C) 2004 Mike Wray + +from xen.xend import XendRoot +xroot = XendRoot.instance() +from SrvDir import SrvDir + +class SrvRoot(SrvDir): + """The root of the xend server. + """ + + """Server sub-components. Each entry is (name, class), where + 'name' is the entry name and 'class' is the name of its class. + """ + #todo Get this list from the XendRoot config. + subdirs = [ + ('node', 'SrvNode' ), + ('domain', 'SrvDomainDir' ), + ('console', 'SrvConsoleDir' ), + ('event', 'SrvEventDir' ), + ('device', 'SrvDeviceDir' ), + ('vnet', 'SrvVnetDir' ), + ] + + def __init__(self): + SrvDir.__init__(self) + for (name, klass) in self.subdirs: + self.add(name, klass) + for (name, klass) in self.subdirs: + self.get(name) + xroot.start() diff --git a/tools/python/xen/xend/server/SrvServer.py b/tools/python/xen/xend/server/SrvServer.py new file mode 100644 index 0000000000..ac201dd10d --- /dev/null +++ b/tools/python/xen/xend/server/SrvServer.py @@ -0,0 +1,59 @@ +#!/usr/bin/python2 +# Copyright (C) 2004 Mike Wray + +"""Example xend HTTP and console server. + + Can be accessed from a browser or from a program. + Do 'python SrvServer.py' to run the server. + Then point a web browser at http://localhost:8000/xend and follow the links. + Most are stubs, except /domain which has a list of domains and a 'create domain' + button. + + You can also access the server from a program. + Do 'python XendClient.py' to run a few test operations. + + The data served differs depending on the client (as defined by User-Agent + and Accept in the HTTP headers). If the client is a browser, data + is returned in HTML, with interactive forms. If the client is a program, + data is returned in SXP format, with no forms. + + The server serves to the world by default. To restrict it to the local host + change 'interface' in main(). + + Mike Wray +""" +# todo Support security settings etc. in the config file. +# todo Support command-line args. + +from twisted.web import server +from twisted.web import resource +from twisted.internet import reactor + +from xen.xend import XendRoot +xroot = XendRoot.instance() + +from xen.xend import Vifctl + +from SrvRoot import SrvRoot + +def create(port=None, interface=None, bridge=0): + if port is None: port = 8000 + if interface is None: interface = '' + if bridge or xroot.rebooted: + init_bridge() + root = resource.Resource() + xend = SrvRoot() + root.putChild('xend', xend) + site = server.Site(root) + reactor.listenTCP(port, site, interface=interface) + +def init_bridge(): + Vifctl.init() + +def main(port=None, interface=None): + create(port, interface) + reactor.run() + + +if __name__ == '__main__': + main() diff --git a/tools/python/xen/xend/server/SrvVnetDir.py b/tools/python/xen/xend/server/SrvVnetDir.py new file mode 100644 index 0000000000..a8a814192d --- /dev/null +++ b/tools/python/xen/xend/server/SrvVnetDir.py @@ -0,0 +1,9 @@ +# Copyright (C) 2004 Mike Wray + +from SrvDir import SrvDir + +class SrvVnetDir(SrvDir): + """Vnet directory. + """ + + pass diff --git a/tools/python/xen/xend/server/__init__.py b/tools/python/xen/xend/server/__init__.py new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/tools/python/xen/xend/server/__init__.py @@ -0,0 +1 @@ + diff --git a/tools/python/xen/xend/server/blkif.py b/tools/python/xen/xend/server/blkif.py new file mode 100755 index 0000000000..4e2a49f7d8 --- /dev/null +++ b/tools/python/xen/xend/server/blkif.py @@ -0,0 +1,341 @@ +from twisted.internet import defer + +from xen.xend import sxp +from xen.xend import PrettyPrint + +import channel +import controller +from messages import * + +class BlkifControllerFactory(controller.ControllerFactory): + """Factory for creating block device interface controllers. + Also handles the 'back-end' channel to the device driver domain. + """ + + def __init__(self): + controller.ControllerFactory.__init__(self) + + self.majorTypes = [ CMSG_BLKIF_BE ] + + self.subTypes = { + CMSG_BLKIF_BE_CREATE : self.recv_be_create, + CMSG_BLKIF_BE_CONNECT : self.recv_be_connect, + CMSG_BLKIF_BE_VBD_CREATE : self.recv_be_vbd_create, + CMSG_BLKIF_BE_VBD_GROW : self.recv_be_vbd_grow, + CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED: self.recv_be_driver_status_changed, + } + self.attached = 1 + self.registerChannel() + + def createInstance(self, dom, recreate=0): + d = self.addDeferred() + blkif = self.getInstanceByDom(dom) + if blkif: + self.callDeferred(blkif) + else: + blkif = BlkifController(self, dom) + self.addInstance(blkif) + if recreate: + self.callDeferred(blkif) + else: + blkif.send_be_create() + return d + + def getDomainDevices(self, dom): + blkif = self.getInstanceByDom(dom) + return (blkif and blkif.getDevices()) or [] + + def getDomainDevice(self, dom, vdev): + blkif = self.getInstanceByDom(dom) + return (blkif and blkif.getDevice(vdev)) or None + + def setControlDomain(self, dom, recreate=0): + if self.dom == dom: return + self.deregisterChannel() + if not recreate: + self.attached = 0 + self.dom = dom + self.registerChannel() + # + #if xend.blkif.be_port: + # xend.blkif.recovery = True + #xend.blkif.be_port = xend.main.port_from_dom(dom) + + def getControlDomain(self): + return self.dom + + def reattachDevice(self, dom, vdev): + blkif = self.getInstanceByDom(dom) + if blkif: + blkif.reattachDevice(vdev) + self.attached = self.devicesAttached() + if self.attached: + self.reattached() + + def devicesAttached(self): + """Check if all devices are attached. + """ + attached = 1 + for blkif in self.getInstances(): + if not blkif.attached: + attached = 0 + break + return attached + + def reattached(self): + for blkif in self.getInstances(): + blkif.reattached() + + def recv_be_create(self, msg, req): + #print 'recv_be_create>' + val = unpackMsg('blkif_be_create_t', msg) + blkif = self.getInstanceByDom(val['domid']) + self.callDeferred(blkif) + + def recv_be_connect(self, msg, req): + #print 'recv_be_create>' + val = unpackMsg('blkif_be_connect_t', msg) + blkif = self.getInstanceByDom(val['domid']) + if blkif: + blkif.send_fe_interface_status_changed() + else: + pass + + def recv_be_vbd_create(self, msg, req): + #print 'recv_be_vbd_create>' + val = unpackMsg('blkif_be_vbd_create_t', msg) + blkif = self.getInstanceByDom(val['domid']) + if blkif: + blkif.send_be_vbd_grow(val['vdevice']) + else: + pass + + def recv_be_vbd_grow(self, msg, req): + #print 'recv_be_vbd_grow>' + val = unpackMsg('blkif_be_vbd_grow_t', msg) + # Check status? + if self.attached: + self.callDeferred(0) + else: + self.reattachDevice(val['domid'], val['vdevice']) + + def recv_be_driver_status_changed(self, msg, req): + val = unpackMsg('blkif_be_driver_status_changed_t', msg) + status = val['status'] + if status == BLKIF_DRIVER_STATUS_UP and not self.attached: + for blkif in self.getInstances(): + blkif.detach() + +class BlkDev(controller.Dev): + """Info record for a block device. + """ + + def __init__(self, ctrl, vdev, mode, segment): + controller.Dev.__init__(self, ctrl) + self.vdev = vdev + self.mode = mode + self.device = segment['device'] + self.start_sector = segment['start_sector'] + self.nr_sectors = segment['nr_sectors'] + self.attached = 1 + + def readonly(self): + return 'w' not in self.mode + + def sxpr(self): + val = ['blkdev', ['vdev', self.vdev], ['mode', self.mode] ] + return val + + def destroy(self): + print 'BlkDev>destroy>', self.vdev + PrettyPrint.prettyprint(self.sxpr()) + self.controller.send_be_vbd_destroy(self.vdev) + +class BlkifController(controller.Controller): + """Block device interface controller. Handles all block devices + for a domain. + """ + + def __init__(self, factory, dom): + #print 'BlkifController> dom=', dom + controller.Controller.__init__(self, factory, dom) + self.devices = {} + + self.majorTypes = [ CMSG_BLKIF_FE ] + + self.subTypes = { + CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED: + self.recv_fe_driver_status_changed, + CMSG_BLKIF_FE_INTERFACE_CONNECT : + self.recv_fe_interface_connect, + } + self.attached = 1 + self.evtchn = None + self.registerChannel() + #print 'BlkifController<', 'dom=', self.dom, 'idx=', self.idx + + def sxpr(self): + val = ['blkif', ['dom', self.dom]] + if self.evtchn: + val.append(['evtchn', + self.evtchn['port1'], + self.evtchn['port2']]) + return val + + def lostChannel(self): + print 'BlkifController>lostChannel>', 'dom=', self.dom + #self.destroyDevices() + controller.Controller.lostChannel(self) + + def getDevices(self): + return self.devices.values() + + def getDevice(self, vdev): + return self.devices.get(vdev) + + def addDevice(self, vdev, mode, segment): + if vdev in self.devices: return None + dev = BlkDev(self, vdev, mode, segment) + self.devices[vdev] = dev + return dev + + def attachDevice(self, vdev, mode, segment, recreate=0): + """Attach a device to the specified interface. + """ + #print 'BlkifController>attach_device>', self.dom, vdev, mode, segment + dev = self.addDevice(vdev, mode, segment) + if not dev: return -1 + if recreate: + d = defer.Deferred() + d.callback(self) + else: + self.send_be_vbd_create(vdev) + d = self.factory.addDeferred() + return d + + def destroy(self): + print 'BlkifController>destroy> dom=', self.dom + def cb_destroy(val): + self.send_be_destroy() + d = self.factory.addDeferred() + d.addCallback(cb_destroy) + self.send_be_disconnect() + #self.destroyDevices() + + def destroyDevices(self): + for dev in self.getDevices(): + dev.destroy() + + def detach(self): + """Detach all devices, when the back-end control domain has changed. + """ + self.attached = 0 + for dev in self.devices.values(): + dev.attached = 0 + self.send_be_vbd_create(vdev) + + def reattachDevice(self, vdev): + """Reattach a device, when the back-end control domain has changed. + """ + dev = self.devices[vdev] + dev.attached = 1 + attached = 1 + for dev in self.devices.values(): + if not dev.attached: + attached = 0 + break + self.attached = attached + return self.attached + + def reattached(self): + """All devices have been reattached after the back-end control + domain has changed. + """ + msg = packMsg('blkif_fe_interface_status_changed_t', + { 'handle' : 0, + 'status' : BLKIF_INTERFACE_STATUS_DISCONNECTED}) + self.writeRequest(msg) + + def recv_fe_driver_status_changed(self, msg, req): + msg = packMsg('blkif_fe_interface_status_changed_t', + { 'handle' : 0, + 'status' : BLKIF_INTERFACE_STATUS_DISCONNECTED, + 'evtchn' : 0 }) + self.writeRequest(msg) + + def recv_fe_interface_connect(self, msg, req): + val = unpackMsg('blkif_fe_interface_connect_t', msg) + self.evtchn = channel.eventChannel(0, self.dom) + print 'recv_fe_interface_connect>' + PrettyPrint.prettyprint(self.sxpr()) + msg = packMsg('blkif_be_connect_t', + { 'domid' : self.dom, + 'blkif_handle' : val['handle'], + 'evtchn' : self.evtchn['port1'], + 'shmem_frame' : val['shmem_frame'] }) + self.factory.writeRequest(msg) + pass + + #def recv_fe_interface_status_changed(self, msg, req): + # (hnd, status, chan) = unpackMsg('blkif_fe_interface_status_changed_t', msg) + # print 'recv_fe_interface_status_changed>', hnd, status, chan + # pass + + def send_fe_interface_status_changed(self): + msg = packMsg('blkif_fe_interface_status_changed_t', + { 'handle' : 0, + 'status' : BLKIF_INTERFACE_STATUS_CONNECTED, + 'evtchn' : self.evtchn['port2'] }) + self.writeRequest(msg) + + def send_be_create(self): + msg = packMsg('blkif_be_create_t', + { 'domid' : self.dom, + 'blkif_handle' : 0 }) + self.factory.writeRequest(msg) + + def send_be_disconnect(self): + print '>BlkifController>send_be_disconnect>', 'dom=', self.dom + msg = packMsg('blkif_be_disconnect_t', + { 'domid' : self.dom, + 'blkif_handle' : 0 }) + self.factory.writeRequest(msg) + + def send_be_destroy(self): + print '>BlkifController>send_be_destroy>', 'dom=', self.dom + msg = packMsg('blkif_be_destroy_t', + { 'domid' : self.dom, + 'blkif_handle' : 0 }) + self.factory.writeRequest(msg) + + def send_be_vbd_create(self, vdev): + dev = self.devices[vdev] + msg = packMsg('blkif_be_vbd_create_t', + { 'domid' : self.dom, + 'blkif_handle' : 0, + 'vdevice' : dev.vdev, + 'readonly' : dev.readonly() }) + self.factory.writeRequest(msg) + + def send_be_vbd_grow(self, vdev): + dev = self.devices[vdev] + msg = packMsg('blkif_be_vbd_grow_t', + { 'domid' : self.dom, + 'blkif_handle' : 0, + 'vdevice' : dev.vdev, + 'extent.device' : dev.device, + 'extent.sector_start' : dev.start_sector, + 'extent.sector_length' : dev.nr_sectors }) + self.factory.writeRequest(msg) + + def send_be_vbd_destroy(self, vdev): + print '>BlkifController>send_be_vbd_destroy>', 'dom=', self.dom, 'vdev=', vdev + PrettyPrint.prettyprint(self.sxpr()) + dev = self.devices[vdev] + msg = packMsg('blkif_be_vbd_destroy_t', + { 'domid' : self.dom, + 'blkif_handle' : 0, + 'vdevice' : dev.vdev }) + del self.devices[vdev] + self.factory.writeRequest(msg) + diff --git a/tools/python/xen/xend/server/channel.py b/tools/python/xen/xend/server/channel.py new file mode 100755 index 0000000000..be98a37fd5 --- /dev/null +++ b/tools/python/xen/xend/server/channel.py @@ -0,0 +1,378 @@ +import xen.ext.xc; xc = xen.ext.xc.new() +from xen.ext import xu +from messages import msgTypeName + +VIRQ_MISDIRECT = 0 # Catch-all interrupt for unbound VIRQs. +VIRQ_TIMER = 1 # Timebase update, and/or requested timeout. +VIRQ_DEBUG = 2 # Request guest to dump debug info. +VIRQ_CONSOLE = 3 # (DOM0) bytes received on emergency console. +VIRQ_DOM_EXC = 4 # (DOM0) Exceptional event for some domain. + +def eventChannel(dom1, dom2): + return xc.evtchn_bind_interdomain(dom1=dom1, dom2=dom2) + +class ChannelFactory: + """Factory for creating channels. + Maintains a table of channels. + """ + + """ Channels indexed by index. """ + channels = {} + + def __init__(self): + """Constructor - do not use. Use the channelFactory function.""" + self.notifier = xu.notifier() + + def addChannel(self, channel): + """Add a channel. + """ + idx = channel.idx + self.channels[idx] = channel + self.notifier.bind(idx) + # Try to wake it up + #self.notifier.unmask(idx) + #channel.notify() + + def getChannel(self, idx): + """Get the channel with the given index (if any). + """ + return self.channels.get(idx) + + def delChannel(self, idx): + """Remove the channel with the given index (if any). + """ + if idx in self.channels: + del self.channels[idx] + self.notifier.unbind(idx) + + def domChannel(self, dom): + """Get the channel for the given domain. + Construct if necessary. + """ + dom = int(dom) + for chan in self.channels.values(): + if not isinstance(chan, Channel): continue + if chan.dom == dom: + return chan + chan = Channel(self, dom) + self.addChannel(chan) + return chan + + def virqChannel(self, virq): + """Get the channel for the given virq. + Construct if necessary. + """ + for chan in self.channels.values(): + if not isinstance(chan, VirqChannel): continue + if chan.virq == virq: + return chan + chan = VirqChannel(self, virq) + self.addChannel(chan) + return chan + + def channelClosed(self, channel): + """The given channel has been closed - remove it. + """ + self.delChannel(channel.idx) + + def createPort(self, dom): + """Create a port for a channel to the given domain. + """ + return xu.port(dom) + +def channelFactory(): + """Singleton constructor for the channel factory. + Use this instead of the class constructor. + """ + global inst + try: + inst + except: + inst = ChannelFactory() + return inst + +class BaseChannel: + """Abstract superclass for channels. + + The subclass constructor must set idx to the port to use. + """ + + def __init__(self, factory): + self.factory = factory + self.idx = -1 + self.closed = 0 + + def getIndex(self): + """Get the channel index. + """ + return self.idx + + def notificationReceived(self, type): + """Called when a notification is received. + Closes the channel on error, otherwise calls + handleNotification(type), which should be defined + in a subclass. + """ + #print 'notificationReceived> type=', type, self + if self.closed: return + if type == self.factory.notifier.EXCEPTION: + print 'notificationReceived> EXCEPTION' + info = xc.evtchn_status(self.idx) + if info['status'] == 'unbound': + print 'notificationReceived> EXCEPTION closing...' + self.close() + return + self.handleNotification(type) + + def close(self): + """Close the channel. Calls channelClosed() on the factory. + Override in subclass. + """ + self.factory.channelClosed(self) + + def handleNotification(self, type): + """Handle notification. + Define in subclass. + """ + pass + + +class VirqChannel(BaseChannel): + """A channel for handling a virq. + """ + + def __init__(self, factory, virq): + """Create a channel for the given virq using the given factory. + + Do not call directly, use virqChannel on the factory. + """ + BaseChannel.__init__(self, factory) + self.virq = virq + # Notification port (int). + self.port = xc.evtchn_bind_virq(virq) + self.idx = self.port + # Clients to call when a virq arrives. + self.clients = [] + + def __repr__(self): + return ('' + % (self.virq, self.port)) + + def getVirq(self): + """Get the channel's virq. + """ + return self.virq + + def close(self): + """Close the channel. Calls lostChannel(self) on all its clients and + channelClosed() on the factory. + """ + for c in self.clients: + c.lostChannel(self) + del self.clients + BaseChannel.close(self) + + def registerClient(self, client): + """Register a client. The client will be called with + client.virqReceived(virq) when a virq is received. + The client will be called with client.lostChannel(self) if the + channel is closed. + """ + self.clients.append(client) + + def handleNotification(self, type): + for c in self.clients: + c.virqReceived(self.virq) + + def notify(self): + xc.evtchn_send(self.port) + + +class Channel(BaseChannel): + """A control channel to a domain. Messages for the domain device controllers + are multiplexed over the channel (console, block devs, net devs). + """ + + def __init__(self, factory, dom): + """Create a channel to the given domain using the given factory. + + Do not call directly, use domChannel on the factory. + """ + BaseChannel.__init__(self, factory) + # Domain. + self.dom = int(dom) + # Domain port (object). + self.port = self.factory.createPort(dom) + # Channel port (int). + self.idx = self.port.local_port + # Registered devices. + self.devs = [] + # Devices indexed by the message types they handle. + self.devs_by_type = {} + # Output queue. + self.queue = [] + self.closed = 0 + + def getLocalPort(self): + """Get the local port. + """ + return self.port.local_port + + def getRemotePort(self): + """Get the remote port. + """ + return self.port.remote_port + + def close(self): + """Close the channel. Calls lostChannel() on all its devices and + channelClosed() on the factory. + """ + self.closed = 1 + for d in self.devs: + d.lostChannel() + self.factory.channelClosed(self) + self.devs = [] + self.devs_by_type = {} + + def registerDevice(self, types, dev): + """Register a device controller. + + @param types message types the controller handles + @param dev device controller + """ + if self.closed: return + self.devs.append(dev) + for ty in types: + self.devs_by_type[ty] = dev + + def deregisterDevice(self, dev): + """Remove the registration for a device controller. + + @param dev device controller + """ + if dev in self.devs: + self.devs.remove(dev) + types = [ ty for (ty, d) in self.devs_by_type.items() if d == dev ] + for ty in types: + del self.devs_by_type[ty] + + def getDevice(self, type): + """Get the device controller handling a message type. + + @param type message type + @returns controller or None + """ + return self.devs_by_type.get(type) + + def getMessageType(self, msg): + """Get a 2-tuple of the message type and subtype. + """ + hdr = msg.get_header() + return (hdr['type'], hdr.get('subtype')) + + def __repr__(self): + return ('' + % (self.dom, + self.port.local_port, + self.port.remote_port)) + + def handleNotification(self, type): + work = 0 + work += self.handleRequests() + work += self.handleResponses() + work += self.handleWrites() + if work: + self.notify() + + def notify(self): + self.port.notify() + + def handleRequests(self): + work = 0 + while 1: + msg = self.readRequest() + if not msg: break + self.requestReceived(msg) + work += 1 + return work + + def requestReceived(self, msg): + (ty, subty) = self.getMessageType(msg) + #todo: Must respond before writing any more messages. + #todo: Should automate this (respond on write) + self.port.write_response(msg) + dev = self.getDevice(ty) + if dev: + dev.requestReceived(msg, ty, subty) + else: + print ("requestReceived> No device: Message type %s %d:%d" + % (msgTypeName(ty, subty), ty, subty)), self + + def handleResponses(self): + work = 0 + while 1: + msg = self.readResponse() + if not msg: break + self.responseReceived(msg) + work += 1 + return work + + def responseReceived(self, msg): + (ty, subty) = self.getMessageType(msg) + dev = self.getDevice(ty) + if dev: + dev.responseReceived(msg, ty, subty) + else: + print ("responseReceived> No device: Message type %d:%d" + % (msgTypeName(ty, subty), ty, subty)), self + + def handleWrites(self): + work = 0 + # Pull data from producers. + for dev in self.devs: + work += dev.produceRequests() + # Flush the queue. + while self.queue and self.port.space_to_write_request(): + msg = self.queue.pop(0) + self.port.write_request(msg) + work += 1 + return work + + def writeRequest(self, msg, notify=1): + if self.closed: + val = -1 + elif self.writeReady(): + self.port.write_request(msg) + if notify: self.notify() + val = 1 + else: + self.queue.append(msg) + val = 0 + return val + + def writeResponse(self, msg): + if self.closed: return -1 + self.port.write_response(msg) + return 1 + + def writeReady(self): + if self.closed or self.queue: return 0 + return self.port.space_to_write_request() + + def readRequest(self): + if self.closed: + return None + if self.port.request_to_read(): + val = self.port.read_request() + else: + val = None + return val + + def readResponse(self): + if self.closed: + return None + if self.port.response_to_read(): + val = self.port.read_response() + else: + val = None + return val diff --git a/tools/python/xen/xend/server/console.py b/tools/python/xen/xend/server/console.py new file mode 100755 index 0000000000..ab8b22e41e --- /dev/null +++ b/tools/python/xen/xend/server/console.py @@ -0,0 +1,232 @@ + +from twisted.internet import reactor +from twisted.internet import protocol +from twisted.protocols import telnet + +from xen.ext import xu + +from xen.xend import EventServer +eserver = EventServer.instance() + +import controller +from messages import * +from params import * + +"""Telnet binary option.""" +TRANSMIT_BINARY = '0' +WILL = chr(251) +IAC = chr(255) + +class ConsoleProtocol(protocol.Protocol): + """Asynchronous handler for a console TCP socket. + """ + + def __init__(self, controller, idx): + self.controller = controller + self.idx = idx + self.addr = None + self.binary = 0 + + def connectionMade(self): + peer = self.transport.getPeer() + self.addr = (peer.host, peer.port) + if self.controller.connect(self.addr, self): + self.transport.write("Cannot connect to console %d on domain %d\n" + % (self.idx, self.controller.dom)) + self.loseConnection() + return + else: + # KAF: A nice quiet successful connect. Don't bother with telnet + # control sequence -- telnet is not the appropriate protocol here. + #self.transport.write("Connected to console %d on domain %d\n" + # % (self.idx, self.controller.dom)) + #self.setTelnetTransmitBinary() + eserver.inject('xend.console.connect', + [self.idx, self.addr[0], self.addr[1]]) + + def setTelnetTransmitBinary(self): + """Send the sequence to set the telnet TRANSMIT-BINARY option. + """ + self.write(IAC + WILL + TRANSMIT_BINARY) + + def dataReceived(self, data): + if self.controller.handleInput(self, data): + self.loseConnection() + + def write(self, data): + #if not self.connected: return -1 + self.transport.write(data) + return len(data) + + def connectionLost(self, reason=None): + eserver.inject('xend.console.disconnect', + [self.idx, self.addr[0], self.addr[1]]) + self.controller.disconnect() + + def loseConnection(self): + self.transport.loseConnection() + +class ConsoleFactory(protocol.ServerFactory): + """Asynchronous handler for a console server socket. + """ + protocol = ConsoleProtocol + + def __init__(self, controller, idx): + #protocol.ServerFactory.__init__(self) + self.controller = controller + self.idx = idx + + def buildProtocol(self, addr): + proto = self.protocol(self.controller, self.idx) + proto.factory = self + return proto + +class ConsoleControllerFactory(controller.ControllerFactory): + """Factory for creating console controllers. + """ + + def createInstance(self, dom, console_port=None): + if console_port is None: + console_port = CONSOLE_PORT_BASE + dom + console = ConsoleController(self, dom, console_port) + self.addInstance(console) + eserver.inject('xend.console.create', + [console.idx, console.dom, console.console_port]) + return console + + def consoleClosed(self, console): + eserver.inject('xend.console.close', console.idx) + self.delInstance(console) + +class ConsoleController(controller.Controller): + """Console controller for a domain. + Does not poll for i/o itself, but relies on the notifier to post console + output and the connected TCP sockets to post console input. + """ + + def __init__(self, factory, dom, console_port): + #print 'ConsoleController> dom=', dom, type(dom) + controller.Controller.__init__(self, factory, dom) + self.majorTypes = [ CMSG_CONSOLE ] + self.status = "new" + self.addr = None + self.conn = None + self.rbuf = xu.buffer() + self.wbuf = xu.buffer() + self.console_port = console_port + + self.registerChannel() + self.listener = None + self.listen() + #print 'ConsoleController<', 'dom=', self.dom, 'idx=', self.idx + + def sxpr(self): + val =['console', + ['status', self.status ], + ['id', self.idx ], + ['domain', self.dom ], + ['local_port', self.channel.getLocalPort() ], + ['remote_port', self.channel.getRemotePort() ], + ['console_port', self.console_port ] ] + if self.addr: + val.append(['connected', self.addr[0], self.addr[1]]) + return val + + def ready(self): + return not (self.closed() or self.rbuf.empty()) + + def closed(self): + return self.status == 'closed' + + def connected(self): + return self.status == 'connected' + + def close(self): + try: + #print 'ConsoleController> close dom=', self.dom + self.status = "closed" + if self.conn: + self.conn.loseConnection() + self.listener.stopListening() + self.deregisterChannel() + self.lostChannel() + except Exception, ex: + print 'ConsoleController>close>', ex + raise + + def listen(self): + """Listen for TCP connections to the console port.. + """ + if self.closed(): return + self.status = "listening" + if self.listener: + #self.listener.startListening() + pass + else: + f = ConsoleFactory(self, self.idx) + self.listener = reactor.listenTCP(self.console_port, f) + + def connect(self, addr, conn): + if self.closed(): return -1 + if self.connected(): return -1 + self.addr = addr + self.conn = conn + self.status = "connected" + self.handleOutput() + return 0 + + def disconnect(self): + if self.conn: + self.conn.loseConnection() + self.addr = None + self.conn = None + self.listen() + + def requestReceived(self, msg, type, subtype): + #print '***Console', self.dom, msg.get_payload() + self.rbuf.write(msg.get_payload()) + self.handleOutput() + + def responseReceived(self, msg, type, subtype): + pass + + def produceRequests(self): + # Send as much pending console data as there is room for. + work = 0 + while not self.wbuf.empty() and self.channel.writeReady(): + msg = xu.message(CMSG_CONSOLE, 0, 0) + msg.append_payload(self.wbuf.read(msg.MAX_PAYLOAD)) + work += self.channel.writeRequest(msg, notify=0) + return work + + def handleInput(self, conn, data): + """Handle some external input aimed at the console. + Called from a TCP connection (conn). + """ + if self.closed(): return -1 + if conn != self.conn: return 0 + self.wbuf.write(data) + if self.produceRequests(): + self.channel.notify() + return 0 + + def handleOutput(self): + """Handle buffered output from the console. + Sends it to the connected console (if any). + """ + if self.closed(): + #print 'Console>handleOutput> closed' + return -1 + if not self.conn: + #print 'Console>handleOutput> not connected' + return 0 + while not self.rbuf.empty(): + try: + #print 'Console>handleOutput> writing...' + bytes = self.conn.write(self.rbuf.peek()) + if bytes > 0: + self.rbuf.discard(bytes) + except socket.error, error: + pass + #print 'Console>handleOutput<' + return 0 diff --git a/tools/python/xen/xend/server/controller.py b/tools/python/xen/xend/server/controller.py new file mode 100755 index 0000000000..900c2d55b0 --- /dev/null +++ b/tools/python/xen/xend/server/controller.py @@ -0,0 +1,169 @@ +from twisted.internet import defer + +import channel +from messages import msgTypeName + +class CtrlMsgRcvr: + """Abstract class for things that deal with a control interface to a domain. + """ + + + def __init__(self): + self.channelFactory = channel.channelFactory() + self.majorTypes = [ ] + self.subTypes = {} + self.dom = None + self.channel = None + self.idx = None + + def requestReceived(self, msg, type, subtype): + method = self.subTypes.get(subtype) + if method: + method(msg, 1) + else: + print ('requestReceived> No handler: Message type %s %d:%d' + % (msgTypeName(type, subtype), type, subtype)), self + + def responseReceived(self, msg, type, subtype): + method = self.subTypes.get(subtype) + if method: + method(msg, 0) + else: + print ('responseReceived> No handler: Message type %s %d:%d' + % (msgTypeName(type, subtype), type, subtype)), self + + def lostChannel(self): + pass + + def registerChannel(self): + #print 'CtrlMsgRcvr>registerChannel>', self + self.channel = self.channelFactory.domChannel(self.dom) + self.idx = self.channel.getIndex() + if self.majorTypes: + self.channel.registerDevice(self.majorTypes, self) + + def deregisterChannel(self): + #print 'CtrlMsgRcvr>deregisterChannel>', self + if self.channel: + self.channel.deregisterDevice(self) + del self.channel + + def produceRequests(self): + return 0 + + def writeRequest(self, msg): + if self.channel: + self.channel.writeRequest(msg) + else: + print 'CtrlMsgRcvr>writeRequest>', 'no channel!', self + + def writeResponse(self, msg): + if self.channel: + self.channel.writeResponse(msg) + else: + print 'CtrlMsgRcvr>writeResponse>', 'no channel!', self + +class ControllerFactory(CtrlMsgRcvr): + """Abstract class for factories creating controllers. + Maintains a table of instances. + """ + + def __init__(self): + CtrlMsgRcvr.__init__(self) + self.instances = {} + self.dlist = [] + self.dom = 0 + # Timeout (in seconds) for deferreds. + self.timeout = 10 + + def addInstance(self, instance): + self.instances[instance.idx] = instance + + def getInstance(self, idx): + return self.instances.get(idx) + + def getInstances(self): + return self.instances.values() + + def getInstanceByDom(self, dom): + for inst in self.instances.values(): + if inst.dom == dom: + return inst + return None + + def delInstance(self, instance): + #print 'ControllerFactory>delInstance>', instance.idx + if instance.idx in self.instances: + #print 'ControllerFactory>delInstance> remove', instance.idx + del self.instances[instance.idx] + + def createInstance(self, dom, recreate=0): + raise NotImplementedError() + + def instanceClosed(self, instance): + #print 'ControllerFactory>instanceClosed>', instance.idx, instance + self.delInstance(instance) + + def addDeferred(self): + d = defer.Deferred() + if self.timeout > 0: + # The deferred will error if not called before timeout. + d.setTimeout(self.timeout) + self.dlist.append(d) + return d + + def callDeferred(self, *args): + if self.dlist: + d = self.dlist.pop(0) + d.callback(*args) + + def errDeferred(self, *args): + if self.dlist: + d = self.dlist.pop(0) + d.errback(*args) + +class Controller(CtrlMsgRcvr): + """Abstract class for a device controller attached to a domain. + """ + + def __init__(self, factory, dom): + CtrlMsgRcvr.__init__(self) + self.factory = factory + self.dom = int(dom) + self.channel = None + self.idx = None + + def close(self): + self.deregisterChannel() + self.lostChannel() + + def lostChannel(self): + #print 'Controller>lostChannel>', self, self.factory + self.factory.instanceClosed(self) + +class Dev: + + def __init__(self, controller): + self.controller = controller + self.props = {} + + def setprop(self, k, v): + self.props[k] = v + + def getprop(self, k, v=None): + return self.props.get(k, v) + + def hasprop(self, k): + return k in self.props + + def delprop(self, k): + if k in self.props: + del self.props[k] + + #def __repr__(self): + # return str(self.sxpr()) + + def sxpr(self): + raise NotImplementedError() + + diff --git a/tools/python/xen/xend/server/cstruct.py b/tools/python/xen/xend/server/cstruct.py new file mode 100755 index 0000000000..880931b41f --- /dev/null +++ b/tools/python/xen/xend/server/cstruct.py @@ -0,0 +1,269 @@ +import struct + +class Struct: + + maxDepth = 10 + + base = ['x', 'B', 'H', 'I', 'L', 'Q', 'c', 'h', 'i', 'l', 'q', ] + + sizes = {'B': 1, + 'H': 2, + 'I': 4, + 'L': 4, + 'Q': 8, + 'c': 1, + 'h': 2, + 'i': 4, + 'l': 4, + 'q': 8, + 'x': 1, + } + + formats = { + 'int8' : 'B', + 'int16' : 'H', + 'int32' : 'I', + 'int64' : 'Q', + 'u8' : 'B', + 'u16' : 'H', + 'u32' : 'I', + 'u64' : 'Q' + } + + def typedef(self, name, val): + self.formats[name] = val + + def struct(self, name, *f): + self.typedef(name, StructInfo(self, f)) + + def getType(self, name): + return self.formats[name] + + def format(self, ty): + d = 0 + f = ty + while d < self.maxDepth: + d += 1 + f = self.formats[f] + if isinstance(f, StructInfo): + return f.format() + if f in self.base: + return f + return -1 + + def alignedformat(self, ty): + fmt = self.format(ty) + #print 'alignedformat> %s |%s|' %(ty, fmt) + afmt = self.align(fmt) + #print 'alignedformat< %s |%s| |%s|' % (ty, fmt, afmt) + return afmt + + def align(self, fmt): + n1 = 0 + afmt = '' + for a in fmt: + n2 = self.getSize(a) + m = n1 % n2 + if m: + d = (n2 - m) + afmt += 'x' * d + n1 += d + afmt += a + n1 += n2 + return afmt + + def fmtsize(self, fmt): + s = 0 + for f in fmt: + s += self.getSize(f) + return s + + def getSize(self, f): + return self.sizes[f] + + def pack(self, ty, data): + return self.getType(ty).pack(data) + + def unpack(self, ty, data): + return self.getType(ty).unpack(data) + + def show(self): + l = self.formats.keys() + l.sort() + for v in l: + print "%-35s %-10s %s" % (v, self.format(v), self.alignedformat(v)) + + +class StructInfo: + + def __init__(self, s, f): + self.fmt = None + self.structs = s + self.fields = f + + def alignedformat(self): + if self.afmt: return self.afmt + self.afmt = self.structs.align(self.format()) + return self.afmt + + def format(self): + if self.fmt: return self.fmt + fmt = "" + for (ty, name) in self.fields: + fmt += self.formatString(ty) + self.fmt = fmt + return fmt + + def formatString(self, ty): + if ty in self.fields: + ty = self.fields[ty] + return self.structs.format(ty) + + def pack(self, *args): + return struct.pack(self.alignedformat(), *args) + + def unpack(self, data): + return struct.unpack(self.alignedformat(), data) + +types = Struct() + +types.typedef('short' , 'h') +types.typedef('int' , 'i') +types.typedef('long' , 'l') +types.typedef('unsigned short', 'H') +types.typedef('unsigned int' , 'I') +types.typedef('unsigned long' , 'L') +types.typedef('domid_t' , 'u64') +types.typedef('blkif_vdev_t' , 'u16') +types.typedef('blkif_pdev_t' , 'u16') +types.typedef('blkif_sector_t', 'u64') + +types.struct('u8[6]', + ('u8', 'a1'), + ('u8', 'a2'), + ('u8', 'a3'), + ('u8', 'a4'), + ('u8', 'a5'), + ('u8', 'a6')) + +types.struct('blkif_fe_interface_status_changed_t', + ('unsigned int', 'handle'), + ('unsigned int', 'status'), + ('unsigned int', 'evtchn')) + +types.struct('blkif_fe_driver_status_changed_t', + ('unsigned int', 'status'), + ('unsigned int', 'nr_interfaces')) + +types.struct('blkif_fe_interface_connect_t', + ('unsigned int' , 'handle'), + ('unsigned long', 'shmem_frame')) + +types.struct('blkif_fe_interface_disconnect_t', + ('unsigned int', 'handle')) + +types.struct('blkif_extent_t', + ('blkif_pdev_t' , 'device'), + ('blkif_sector_t', 'sector_start'), + ('blkif_sector_t', 'sector_length')) + +types.struct('blkif_be_create_t', + ('domid_t' , 'domid'), + ('unsigned int', 'blkif_handle'), + ('unsigned int', 'status')) + +types.struct('blkif_be_destroy_t', + ('domid_t' , 'domid'), + ('unsigned int', 'blkif_handle'), + ('unsigned int', 'status')) + +types.struct('blkif_be_connect_t', + ('domid_t' , 'domid'), + ('unsigned int' , 'blkif_handle'), + ('unsigned int' , 'evtchn'), + ('unsigned long', 'shmem_frame'), + ('unsigned int' , 'status')) + +types.struct('blkif_be_disconnect_t', + ('domid_t' , 'domid'), + ('unsigned int', 'blkif_handle'), + ('unsigned int', 'status')) + +types.struct('blkif_be_vbd_create_t', + ('domid_t' , 'domid'), #Q + ('unsigned int', 'blkif_handle'), #I + ('blkif_vdev_t', 'vdevice'), #H + ('int' , 'readonly'), #i + ('unsigned int', 'status')) #I + +types.struct('blkif_be_vbd_destroy_t', + ('domid_t' , 'domid'), + ('unsigned int', 'blkif_handle'), + ('blkif_vdev_t', 'vdevice'), + ('unsigned int', 'status')) + +types.struct('blkif_be_vbd_grow_t', + ('domid_t' , 'domid'), #Q + ('unsigned int' , 'blkif_handle'), #I + ('blkif_vdev_t' , 'vdevice'), #H + ('blkif_extent_t', 'extent'), #HQQ + ('unsigned int' , 'status')) #I + +types.struct('blkif_be_vbd_shrink_t', + ('domid_t' , 'domid'), + ('unsigned int', 'blkif_handle'), + ('blkif_vdev_t', 'vdevice'), + ('unsigned int', 'status')) + +types.struct('blkif_be_driver_status_changed_t', + ('unsigned int', 'status'), + ('unsigned int', 'nr_interfaces')) + +types.struct('netif_fe_interface_status_changed_t', + ('unsigned int', 'handle'), + ('unsigned int', 'status'), + ('unsigned int', 'evtchn'), + ('u8[6]', 'mac')) + +types.struct('netif_fe_driver_status_changed_t', + ('unsigned int', 'status'), + ('unsigned int', 'nr_interfaces')) + +types.struct('netif_fe_interface_connect_t', + ('unsigned int', 'handle'), + ('unsigned long', 'tx_shmem_frame'), + ('unsigned long', 'rx_shmem_frame')) + +types.struct('netif_fe_interface_disconnect_t', + ('unsigned int', 'handle')) + +types.struct('netif_be_create_t', + ('domid_t' , 'domid'), + ('unsigned int', 'netif_handle'), + ('u8[6]' , 'mac'), + ('unsigned int', 'status')) + +types.struct('netif_be_destroy_t', + ('domid_t' , 'domid'), + ('unsigned int', 'netif_handle'), + ('unsigned int', 'status')) + +types.struct('netif_be_connect_t', + ('domid_t' , 'domid'), + ('unsigned int' , 'netif_handle'), + ('unsigned int' , 'evtchn'), + ('unsigned long', 'tx_shmem_frame'), + ('unsigned long', 'rx_shmem_frame'), + ('unsigned int' , 'status')) + +types.struct('netif_be_disconnect_t', + ('domid_t' , 'domid'), + ('unsigned int', 'netif_handle'), + ('unsigned int', 'status')) + +types.struct('netif_be_driver_status_changed_t', + ('unsigned int', 'status'), + ('unsigned int', 'nr_interfaces')) + +if 1 or __name__ == "__main__": + types.show() diff --git a/tools/python/xen/xend/server/domain.py b/tools/python/xen/xend/server/domain.py new file mode 100644 index 0000000000..ab22234480 --- /dev/null +++ b/tools/python/xen/xend/server/domain.py @@ -0,0 +1,41 @@ +import channel +import controller +from messages import * + +class DomainControllerFactory(controller.ControllerFactory): + """Factory for creating domain controllers. + """ + + def createInstance(self, dom): + d = DomainController(self, dom) + self.addInstance(d) + return d + + def getInstanceByDom(self, dom): + for inst in self.instances.values(): + if inst.dom == dom: + return inst + inst = self.createInstance(dom) + return inst + + +class DomainController(controller.Controller): + """Generic controller for a domain. + """ + + reasons = {'poweroff' : 'shutdown_poweroff_t', + 'reboot' : 'shutdown_reboot_t', + 'suspend' : 'shutdown_suspend_t' } + + def __init__(self, factory, dom): + controller.Controller.__init__(self, factory, dom) + self.majorTypes = [ CMSG_SHUTDOWN ] + self.registerChannel() + print 'DomainController>', self, self.channel, self.idx + + def shutdown(self, reason): + msgtype = self.reasons.get(reason) + if not msgtype: + raise ValueError('invalid reason:' + reason) + msg = packMsg(msgtype, {}) + self.writeRequest(msg) diff --git a/tools/python/xen/xend/server/messages.py b/tools/python/xen/xend/server/messages.py new file mode 100644 index 0000000000..e12d7b6e24 --- /dev/null +++ b/tools/python/xen/xend/server/messages.py @@ -0,0 +1,219 @@ +import struct + +from xen.ext import xu + +DEBUG = 0 + +""" All message formats. +Added to incrementally for the various message types. +See below. +""" +msg_formats = {} + +#============================================================================ +# Console message types. +#============================================================================ + +CMSG_CONSOLE = 0 + +console_formats = { 'console_data': (CMSG_CONSOLE, 0) } + +msg_formats.update(console_formats) + +#============================================================================ +# Block interface message types. +#============================================================================ + +CMSG_BLKIF_BE = 1 +CMSG_BLKIF_FE = 2 + +CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED = 0 +CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED = 32 +CMSG_BLKIF_FE_INTERFACE_CONNECT = 33 +CMSG_BLKIF_FE_INTERFACE_DISCONNECT = 34 + +CMSG_BLKIF_BE_CREATE = 0 +CMSG_BLKIF_BE_DESTROY = 1 +CMSG_BLKIF_BE_CONNECT = 2 +CMSG_BLKIF_BE_DISCONNECT = 3 +CMSG_BLKIF_BE_VBD_CREATE = 4 +CMSG_BLKIF_BE_VBD_DESTROY = 5 +CMSG_BLKIF_BE_VBD_GROW = 6 +CMSG_BLKIF_BE_VBD_SHRINK = 7 +CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED = 32 + +BLKIF_DRIVER_STATUS_DOWN = 0 +BLKIF_DRIVER_STATUS_UP = 1 + +BLKIF_INTERFACE_STATUS_DESTROYED = 0 #/* Interface doesn't exist. */ +BLKIF_INTERFACE_STATUS_DISCONNECTED = 1 #/* Exists but is disconnected. */ +BLKIF_INTERFACE_STATUS_CONNECTED = 2 #/* Exists and is connected. */ + +BLKIF_BE_STATUS_OKAY = 0 +BLKIF_BE_STATUS_ERROR = 1 +BLKIF_BE_STATUS_INTERFACE_EXISTS = 2 +BLKIF_BE_STATUS_INTERFACE_NOT_FOUND = 3 +BLKIF_BE_STATUS_INTERFACE_CONNECTED = 4 +BLKIF_BE_STATUS_VBD_EXISTS = 5 +BLKIF_BE_STATUS_VBD_NOT_FOUND = 6 +BLKIF_BE_STATUS_OUT_OF_MEMORY = 7 +BLKIF_BE_STATUS_EXTENT_NOT_FOUND = 8 +BLKIF_BE_STATUS_MAPPING_ERROR = 9 + +blkif_formats = { + 'blkif_be_connect_t': + (CMSG_BLKIF_BE, CMSG_BLKIF_BE_CONNECT), + + 'blkif_be_create_t': + (CMSG_BLKIF_BE, CMSG_BLKIF_BE_CREATE), + + 'blkif_be_disconnect_t': + (CMSG_BLKIF_BE, CMSG_BLKIF_BE_DISCONNECT), + + 'blkif_be_destroy_t': + (CMSG_BLKIF_BE, CMSG_BLKIF_BE_DESTROY), + + 'blkif_be_vbd_create_t': + (CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_CREATE), + + 'blkif_be_vbd_grow_t': + (CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_GROW), + + 'blkif_be_vbd_destroy_t': + (CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_DESTROY), + + 'blkif_fe_interface_status_changed_t': + (CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED), + + 'blkif_fe_driver_status_changed_t': + (CMSG_BLKIF_FE, CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED), + + 'blkif_fe_interface_connect_t': + (CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_CONNECT), +} + +msg_formats.update(blkif_formats) + +#============================================================================ +# Network interface message types. +#============================================================================ + +CMSG_NETIF_BE = 3 +CMSG_NETIF_FE = 4 + +CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED = 0 +CMSG_NETIF_FE_DRIVER_STATUS_CHANGED = 32 +CMSG_NETIF_FE_INTERFACE_CONNECT = 33 +CMSG_NETIF_FE_INTERFACE_DISCONNECT = 34 + +CMSG_NETIF_BE_CREATE = 0 +CMSG_NETIF_BE_DESTROY = 1 +CMSG_NETIF_BE_CONNECT = 2 +CMSG_NETIF_BE_DISCONNECT = 3 +CMSG_NETIF_BE_DRIVER_STATUS_CHANGED = 32 + +NETIF_INTERFACE_STATUS_DESTROYED = 0 #/* Interface doesn't exist. */ +NETIF_INTERFACE_STATUS_DISCONNECTED = 1 #/* Exists but is disconnected. */ +NETIF_INTERFACE_STATUS_CONNECTED = 2 #/* Exists and is connected. */ + +NETIF_DRIVER_STATUS_DOWN = 0 +NETIF_DRIVER_STATUS_UP = 1 + +netif_formats = { + 'netif_be_connect_t': + (CMSG_NETIF_BE, CMSG_NETIF_BE_CONNECT), + + 'netif_be_create_t': + (CMSG_NETIF_BE, CMSG_NETIF_BE_CREATE), + + 'netif_be_disconnect_t': + (CMSG_NETIF_BE, CMSG_NETIF_BE_DISCONNECT), + + 'netif_be_destroy_t': + (CMSG_NETIF_BE, CMSG_NETIF_BE_DESTROY), + + 'netif_be_driver_status_changed_t': + (CMSG_NETIF_BE, CMSG_NETIF_BE_DRIVER_STATUS_CHANGED), + + 'netif_fe_driver_status_changed_t': + (CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED), + + 'netif_fe_interface_connect_t': + (CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_CONNECT), + + 'netif_fe_interface_status_changed_t': + (CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED), + } + +msg_formats.update(netif_formats) + +#============================================================================ +CMSG_SHUTDOWN = 6 + +CMSG_SHUTDOWN_POWEROFF = 0 +CMSG_SHUTDOWN_REBOOT = 1 +CMSG_SHUTDOWN_SUSPEND = 2 + +STOPCODE_shutdown = 0 +STOPCODE_reboot = 1 +STOPCODE_suspend = 2 + +shutdown_formats = { + 'shutdown_poweroff_t': + (CMSG_SHUTDOWN, CMSG_SHUTDOWN_POWEROFF), + + 'shutdown_reboot_t': + (CMSG_SHUTDOWN, CMSG_SHUTDOWN_REBOOT), + + 'shutdown_suspend_t': + (CMSG_SHUTDOWN, CMSG_SHUTDOWN_SUSPEND), + } + +msg_formats.update(shutdown_formats) + +#============================================================================ + +class Msg: + pass + +def packMsg(ty, params): + if DEBUG: print '>packMsg', ty, params + (major, minor) = msg_formats[ty] + args = {} + for (k, v) in params.items(): + if k == 'mac': + for i in range(0, 6): + args['mac[%d]' % i] = v[i] + else: + args[k] = v + if DEBUG: + for (k, v) in args.items(): + print 'packMsg>', k, v, type(v) + msgid = 0 + msg = xu.message(major, minor, msgid, args) + return msg + +def unpackMsg(ty, msg): + args = msg.get_payload() + mac = [0, 0, 0, 0, 0, 0] + macs = [] + for (k, v) in args.items(): + if k.startswith('mac['): + macs += k + i = int(k[4:5]) + mac[i] = v + else: + pass + if macs: + args['mac'] = mac + for k in macs: + del args[k] + if DEBUG: print 'createInstance> dom=', dom + netif = self.getInstanceByDom(dom) + if netif is None: + netif = NetifController(self, dom) + self.addInstance(netif) + return netif + + def getDomainDevices(self, dom): + netif = self.getInstanceByDom(dom) + return (netif and netif.getDevices()) or [] + + def getDomainDevice(self, dom, vif): + netif = self.getInstanceByDom(dom) + return (netif and netif.getDevice(vif)) or None + + def setControlDomain(self, dom, recreate=0): + """Set the 'back-end' device driver domain. + """ + if self.dom == dom: return + self.deregisterChannel() + if not recreate: + self.attached = 0 + self.dom = dom + self.registerChannel() + # + #if xend.netif.be_port.remote_dom != 0: + # xend.netif.recovery = True + # xend.netif.be_port = xend.main.port_from_dom(dom) + # + + def getControlDomain(self): + return self.dom + + def recv_be_create(self, msg, req): + self.callDeferred(0) + + def recv_be_connect(self, msg, req): + val = unpackMsg('netif_be_connect_t', msg) + dom = val['domid'] + vif = val['netif_handle'] + netif = self.getInstanceByDom(dom) + if netif: + netif.send_interface_connected(vif) + else: + print "recv_be_connect> unknown vif=", vif + pass + + def recv_be_driver_status_changed(self, msg, req): + val = unpackMsg('netif_be_driver_status_changed_t', msg) + status = val['status'] + if status == NETIF_DRIVER_STATUS_UP and not self.attached: + # If we are not attached the driver domain was changed, and + # this signals the new driver domain is ready. + for netif in self.getInstances(): + netif.reattach_devices() + self.attached = 1 + +## pl = msg.get_payload() +## status = pl['status'] +## if status == NETIF_DRIVER_STATUS_UP: +## if xend.netif.recovery: +## print "New netif backend now UP, notifying guests:" +## for netif_key in interface.list.keys(): +## netif = interface.list[netif_key] +## netif.create() +## print " Notifying %d" % netif.dom +## msg = xu.message( +## CMSG_NETIF_FE, +## CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED, 0, +## { 'handle' : 0, 'status' : 1 }) +## netif.ctrlif_tx_req(xend.main.port_from_dom(netif.dom),msg) +## print "Done notifying guests" +## recovery = False + +class NetDev(controller.Dev): + """Info record for a network device. + """ + + def __init__(self, ctrl, vif, mac): + controller.Dev.__init__(self, ctrl) + self.vif = vif + self.mac = mac + self.evtchn = None + self.bridge = None + self.ipaddr = [] + + def sxpr(self): + vif = str(self.vif) + mac = self.get_mac() + val = ['netdev', ['vif', vif], ['mac', mac]] + if self.bridge: + val.append(['bridge', self.bridge]) + if self.evtchn: + val.append(['evtchn', + self.evtchn['port1'], + self.evtchn['port2']]) + return val + + def get_vifname(self): + return "vif%d.%d" % (self.controller.dom, self.vif) + + def get_mac(self): + return ':'.join(map(lambda x: "%x" % x, self.mac)) + + def vifctl_params(self): + return { 'mac' : self.get_mac(), + 'bridge': self.bridge, + 'ipaddr': self.ipaddr } + + def up(self, bridge=None, ipaddr=[]): + self.bridge = bridge + self.ipaddr = ipaddr + Vifctl.up(self.get_vifname(), **self.vifctl_params()) + + def down(self): + Vifctl.down(self.get_vifname(), **self.vifctl_params()) + + def destroy(self): + def cb_destroy(val): + self.controller.send_be_destroy(self.vif) + print 'NetDev>destroy>', 'vif=', self.vif + PrettyPrint.prettyprint(self.sxpr()) + self.down() + d = self.controller.factory.addDeferred() + d.addCallback(cb_destroy) + self.controller.send_be_disconnect(self.vif) + #self.controller.send_be_destroy(self.vif) + + +class NetifController(controller.Controller): + """Network interface controller. Handles all network devices for a domain. + """ + + def __init__(self, factory, dom): + #print 'NetifController> dom=', dom + controller.Controller.__init__(self, factory, dom) + self.devices = {} + + self.majorTypes = [ CMSG_NETIF_FE ] + + self.subTypes = { + CMSG_NETIF_FE_DRIVER_STATUS_CHANGED: + self.recv_fe_driver_status_changed, + CMSG_NETIF_FE_INTERFACE_CONNECT : + self.recv_fe_interface_connect, + } + self.registerChannel() + #print 'NetifController<', 'dom=', self.dom, 'idx=', self.idx + + def sxpr(self): + val = ['netif', ['dom', self.dom]] + return val + + def randomMAC(self): + # VIFs get a random MAC address with a "special" vendor id. + # + # NB. The vendor is currently an "obsolete" one that used to belong + # to DEC (AA-00-00). Using it is probably a bit rude :-) + # + # NB2. The first bit of the first random octet is set to zero for + # all dynamic MAC addresses. This may allow us to manually specify + # MAC addresses for some VIFs with no fear of clashes. + mac = [ 0xaa, 0x00, 0x00, + random.randint(0x00, 0x7f), + random.randint(0x00, 0xff), + random.randint(0x00, 0xff) ] + return mac + + def lostChannel(self): + print 'NetifController>lostChannel>', 'dom=', self.dom + #self.destroyDevices() + controller.Controller.lostChannel(self) + + def getDevices(self): + return self.devices.values() + + def getDevice(self, vif): + return self.devices.get(vif) + + def addDevice(self, vif, vmac): + if vmac is None: + mac = self.randomMAC() + else: + mac = [ int(x, 16) for x in vmac.split(':') ] + if len(mac) != 6: raise ValueError("invalid mac") + #print "attach_device>", "vif=", vif, "mac=", mac + dev = NetDev(self, vif, mac) + self.devices[vif] = dev + return dev + + def destroy(self): + print 'NetifController>destroy>', 'dom=', self.dom + self.destroyDevices() + + def destroyDevices(self): + for dev in self.getDevices(): + dev.destroy() + + def attachDevice(self, vif, vmac, recreate=0): + """Attach a network device. + If vmac is None a random mac address is assigned. + + @param vif interface index + @param vmac mac address (string) + """ + self.addDevice(vif, vmac) + if recreate: + d = defer.Deferred() + d.callback(self) + else: + d = self.factory.addDeferred() + self.send_be_create(vif) + return d + + def reattach_devices(self): + """Reattach all devices when the back-end control domain has changed. + """ + d = self.factory.addDeferred() + self.send_be_create(vif) + self.attach_fe_devices(0) + + def attach_fe_devices(self): + for dev in self.devices.values(): + msg = packMsg('netif_fe_interface_status_changed_t', + { 'handle' : dev.vif, + 'status' : NETIF_INTERFACE_STATUS_DISCONNECTED, + 'evtchn' : 0, + 'mac' : dev.mac }) + self.writeRequest(msg) + + def recv_fe_driver_status_changed(self, msg, req): + if not req: return + msg = packMsg('netif_fe_driver_status_changed_t', + { 'status' : NETIF_DRIVER_STATUS_UP, + 'nr_interfaces' : len(self.devices) }) + self.writeRequest(msg) + self.attach_fe_devices() + + def recv_fe_interface_connect(self, msg, req): + val = unpackMsg('netif_fe_interface_connect_t', msg) + dev = self.devices[val['handle']] + dev.evtchn = channel.eventChannel(0, self.dom) + msg = packMsg('netif_be_connect_t', + { 'domid' : self.dom, + 'netif_handle' : dev.vif, + 'evtchn' : dev.evtchn['port1'], + 'tx_shmem_frame' : val['tx_shmem_frame'], + 'rx_shmem_frame' : val['rx_shmem_frame'] }) + self.factory.writeRequest(msg) + + def send_interface_connected(self, vif): + dev = self.devices[vif] + msg = packMsg('netif_fe_interface_status_changed_t', + { 'handle' : dev.vif, + 'status' : NETIF_INTERFACE_STATUS_CONNECTED, + 'evtchn' : dev.evtchn['port2'], + 'mac' : dev.mac }) + self.writeRequest(msg) + + def send_be_create(self, vif): + dev = self.devices[vif] + msg = packMsg('netif_be_create_t', + { 'domid' : self.dom, + 'netif_handle' : dev.vif, + 'mac' : dev.mac }) + self.factory.writeRequest(msg) + + def send_be_disconnect(self, vif): + dev = self.devices[vif] + msg = packMsg('netif_be_disconnect_t', + { 'domid' : self.dom, + 'netif_handle' : dev.vif }) + self.factory.writeRequest(msg) + + def send_be_destroy(self, vif): + print 'NetifController>send_be_destroy>', 'dom=', self.dom, 'vif=', vif + PrettyPrint.prettyprint(self.sxpr()) + dev = self.devices[vif] + del self.devices[vif] + msg = packMsg('netif_be_destroy_t', + { 'domid' : self.dom, + 'netif_handle' : vif }) + self.factory.writeRequest(msg) diff --git a/tools/python/xen/xend/server/params.py b/tools/python/xen/xend/server/params.py new file mode 100644 index 0000000000..7949f1431f --- /dev/null +++ b/tools/python/xen/xend/server/params.py @@ -0,0 +1,10 @@ +# The following parameters could be placed in a configuration file. +PID_FILE = '/var/run/xend.pid' +LOG_FILE = '/var/log/xend.log' +USER = 'root' +CONTROL_DIR = '/var/run/xend' +MGMT_SOCK = 'xendsock' # relative to CONTROL_DIR +EVENT_PORT = 8001 + +CONSOLE_PORT_BASE = 9600 + diff --git a/tools/python/xen/xend/sxp.py b/tools/python/xen/xend/sxp.py new file mode 100644 index 0000000000..01654a2377 --- /dev/null +++ b/tools/python/xen/xend/sxp.py @@ -0,0 +1,580 @@ +#!/usr/bin/python2 +# Copyright (C) 2004 Mike Wray +""" +Input-driven parsing for s-expression (sxp) format. +Create a parser: pin = Parser(); +Then call pin.input(buf) with your input. +Call pin.input_eof() when done. +Use pin.read() to see if a value has been parsed, pin.get_val() +to get a parsed value. You can call ready and get_val at any time - +you don't have to wait until after calling input_eof. + +""" +from __future__ import generators + +import sys +import types +import errno +import string +from StringIO import StringIO + +__all__ = [ + "mime_type", + "ParseError", + "Parser", + "atomp", + "show", + "show_xml", + "elementp", + "name", + "attributes", + "attribute", + "children", + "child", + "child_at", + "child0", + "child1", + "child2", + "child3", + "child4", + "child_value", + "has_id", + "with_id", + "child_with_id", + "elements", + "parse", + ] + +mime_type = "application/sxp" + +escapes = { + 'a': '\a', + 'b': '\b', + 't': '\t', + 'n': '\n', + 'v': '\v', + 'f': '\f', + 'r': '\r', + '\\': '\\', + '\'': '\'', + '\"': '\"'} + +k_list_open = "(" +k_list_close = ")" +k_attr_open = "@" +k_eval = "!" + +escapes_rev = {} +for k in escapes: + escapes_rev[escapes[k]] = k + +class ParseError(StandardError): + + def __init__(self, parser, value): + self.parser = parser + self.value = value + + def __str__(self): + return self.value + +class ParserState: + + def __init__(self, fn, parent=None): + self.parent = parent + self.buf = '' + self.val = [] + self.delim = None + self.fn = fn + + def push(self, fn): + return ParserState(fn, parent=self) + +class Parser: + + def __init__(self): + self.error = sys.stderr + self.reset() + + def reset(self): + self.val = [] + self.eof = 0 + self.err = 0 + self.line_no = 0 + self.char_no = 0 + self.state = None + + def push_state(self, fn): + self.state = self.state.push(fn) + + def pop_state(self): + val = self.state + self.state = self.state.parent + if self.state and self.state.fn == self.state_start: + # Return to start state - produce the value. + self.val += self.state.val + self.state.val = [] + return val + + def in_class(self, c, s): + return s.find(c) >= 0 + + def in_space_class(self, c): + return self.in_class(c, ' \t\n\v\f\r') + + def is_separator(self, c): + return self.in_class(c, '{}()<>[]!;') + + def in_comment_class(self, c): + return self.in_class(c, '#') + + def in_string_quote_class(self, c): + return self.in_class(c, '"\'') + + def in_printable_class(self, c): + return self.in_class(c, string.printable) + + def set_error_stream(self, error): + self.error = error + + def has_error(self): + return self.err > 0 + + def at_eof(self): + return self.eof + + def input_eof(self): + self.eof = 1 + self.input_char(-1) + + def input(self, buf): + if not buf or len(buf) == 0: + self.input_eof() + else: + for c in buf: + self.input_char(c) + + def input_char(self, c): + if self.at_eof(): + pass + elif c == '\n': + self.line_no += 1 + self.char_no = 0 + else: + self.char_no += 1 + + if self.state is None: + self.begin_start(None) + self.state.fn(c) + + def ready(self): + return len(self.val) > 0 + + def get_val(self): + v = self.val[0] + self.val = self.val[1:] + return v + + def get_all(self): + return self.val + + def begin_start(self, c): + self.state = ParserState(self.state_start) + + def end_start(self): + self.val += self.state.val + self.pop_state() + + def state_start(self, c): + if self.at_eof(): + self.end_start() + elif self.in_space_class(c): + pass + elif self.in_comment_class(c): + self.begin_comment(c) + elif c == k_list_open: + self.begin_list(c) + elif c == k_list_close: + raise ParseError(self, "syntax error: "+c) + elif self.in_string_quote_class(c): + self.begin_string(c) + elif self.in_printable_class(c): + self.begin_atom(c) + elif c == chr(4): + # ctrl-D, EOT: end-of-text. + self.input_eof() + else: + raise ParseError(self, "invalid character: code %d" % ord(c)) + + def begin_comment(self, c): + self.push_state(self.state_comment) + self.state.buf += c + + def end_comment(self): + self.pop_state() + + def state_comment(self, c): + if c == '\n' or self.at_eof(): + self.end_comment() + else: + self.state.buf += c + + def begin_string(self, c): + self.push_state(self.state_string) + self.state.delim = c + + def end_string(self): + val = self.state.buf + self.state.parent.val.append(val) + self.pop_state() + + def state_string(self, c): + if self.at_eof(): + raise ParseError(self, "unexpected EOF") + elif c == self.state.delim: + self.end_string() + elif c == '\\': + self.push_state(self.state_escape) + else: + self.state.buf += c + + def state_escape(self, c): + if self.at_eof(): + raise ParseError(self, "unexpected EOF") + d = escapes.get(c) + if d: + self.state.parent.buf += d + self.pop_state() + elif c == 'x': + self.state.fn = self.state_hex + self.state.val = 0 + else: + self.state.fn = self.state_octal + self.state.val = 0 + self.input_char(c) + + def state_octal(self, c): + def octaldigit(c): + self.state.val *= 8 + self.state.val += ord(c) - ord('0') + self.state.buf += c + if self.state.val < 0 or self.state.val > 0xff: + raise ParseError(self, "invalid octal escape: out of range " + self.state.buf) + if len(self.state.buf) == 3: + octaldone() + + def octaldone(): + d = chr(self.state.val) + self.state.parent.buf += d + self.pop_state() + + if self.at_eof(): + raise ParseError(self, "unexpected EOF") + elif '0' <= c <= '7': + octaldigit(c) + elif len(self.buf): + octaldone() + self.input_char(c) + + def state_hex(self, c): + def hexdone(): + d = chr(self.state.val) + self.state.parent.buf += d + self.pop_state() + + def hexdigit(c, d): + self.state.val *= 16 + self.state.val += ord(c) - ord(d) + self.state.buf += c + if self.state.val < 0 or self.state.val > 0xff: + raise ParseError(self, "invalid hex escape: out of range " + self.state.buf) + if len(self.state.buf) == 2: + hexdone() + + if self.at_eof(): + raise ParseError(self, "unexpected EOF") + elif '0' <= c <= '9': + hexdigit(c, '0') + elif 'A' <= c <= 'F': + hexdigit(c, 'A') + elif 'a' <= c <= 'f': + hexdigit(c, 'a') + elif len(buf): + hexdone() + self.input_char(c) + + def begin_atom(self, c): + self.push_state(self.state_atom) + self.state.buf = c + + def end_atom(self): + val = self.state.buf + self.state.parent.val.append(val) + self.pop_state() + + def state_atom(self, c): + if self.at_eof(): + self.end_atom() + elif (self.is_separator(c) or + self.in_space_class(c) or + self.in_comment_class(c)): + self.end_atom() + self.input_char(c) + else: + self.state.buf += c + + def begin_list(self, c): + self.push_state(self.state_list) + + def end_list(self): + val = self.state.val + self.state.parent.val.append(val) + self.pop_state() + + def state_list(self, c): + if self.at_eof(): + raise ParseError(self, "unexpected EOF") + elif c == k_list_close: + self.end_list() + else: + self.state_start(c) + +def atomp(sxpr): + if sxpr.isalnum() or sxpr == '@': + return 1 + for c in sxpr: + if c in string.whitespace: return 0 + if c in '"\'\\(){}[]<>$#&%^': return 0 + if c in string.ascii_letters: continue + if c in string.digits: continue + if c in '.-_:/~': continue + return 0 + return 1 + +def show(sxpr, out=sys.stdout): + if isinstance(sxpr, types.ListType): + out.write(k_list_open) + i = 0 + for x in sxpr: + if i: out.write(' ') + show(x, out) + i += 1 + out.write(k_list_close) + elif isinstance(sxpr, types.StringType) and atomp(sxpr): + out.write(sxpr) + else: + #out.write("'" + str(sxpr) + "'") + out.write(repr(str(sxpr))) + +def show_xml(sxpr, out=sys.stdout): + if isinstance(sxpr, types.ListType): + element = name(sxpr) + out.write('<%s' % element) + for attr in attributes(sxpr): + out.write(' %s=%s' % (attr[0], attr[1])) + out.write('>') + i = 0 + for x in children(sxpr): + if i: out.write(' ') + show_xml(x, out) + i += 1 + out.write('' % element) + elif isinstance(sxpr, types.StringType) and atomp(sxpr): + out.write(sxpr) + else: + out.write(str(sxpr)) + +def elementp(sxpr, elt=None): + return (isinstance(sxpr, types.ListType) + and len(sxpr) + and (None == elt or sxpr[0] == elt)) + +def name(sxpr): + val = None + if isinstance(sxpr, types.StringType): + val = sxpr + elif isinstance(sxpr, types.ListType) and len(sxpr): + val = sxpr[0] + return val + +def attributes(sxpr): + val = [] + if isinstance(sxpr, types.ListType) and len(sxpr) > 1: + attr = sxpr[1] + if elementp(attr, k_attr_open): + val = attr[1:] + return val + +def attribute(sxpr, key, val=None): + for x in attributes(sxpr): + if x[0] == key: + val = x[1] + break + return val + +def children(sxpr, elt=None): + val = [] + if isinstance(sxpr, types.ListType) and len(sxpr) > 1: + i = 1 + x = sxpr[i] + if elementp(x, k_attr_open): + i += 1 + val = sxpr[i : ] + if elt: + def iselt(x): + return elementp(x, elt) + val = filter(iselt, val) + return val + +def child(sxpr, elt, val=None): + for x in children(sxpr): + if elementp(x, elt): + val = x + break + return val + +def child_at(sxpr, index, val=None): + kids = children(sxpr) + if len(kids) > index: + val = kids[index] + return val + +def child0(sxpr, val=None): + return child_at(sxpr, 0, val) + +def child1(sxpr, val=None): + return child_at(sxpr, 1, val) + +def child2(sxpr, val=None): + return child_at(sxpr, 2, val) + +def child3(sxpr, val=None): + return child_at(sxpr, 3, val) + +def child4(sxpr, val=None): + return child_at(sxpr, 4, val) + +def child_value(sxpr, elt, val=None): + kid = child(sxpr, elt) + if kid: + val = child_at(kid, 0, val) + return val + +def has_id(sxpr, id): + """Test if an s-expression has a given id. + """ + return attribute(sxpr, 'id') == id + +def with_id(sxpr, id, val=None): + """Find the first s-expression with a given id, at any depth. + + sxpr s-exp or list + id id + val value if not found (default None) + + return s-exp or val + """ + if isinstance(sxpr, types.ListType): + for n in sxpr: + if has_id(n, id): + val = n + break + v = with_id(n, id) + if v is None: continue + val = v + break + return val + +def child_with_id(sxpr, id, val=None): + """Find the first child with a given id. + + sxpr s-exp or list + id id + val value if not found (default None) + + return s-exp or val + """ + if isinstance(sxpr, types.ListType): + for n in sxpr: + if has_id(n, id): + val = n + break + return val + +def elements(sxpr, ctxt=None): + """Generate elements (at any depth). + Visit elements in pre-order. + Values generated are (node, context) + The context is None if there is no parent, otherwise + (index, parent, context) where index is the node's index w.r.t its parent, + and context is the parent's context. + + sxpr s-exp + + returns generator + """ + yield (sxpr, ctxt) + i = 0 + for n in children(sxpr): + if isinstance(n, types.ListType): + # Calling elements() recursively does not generate recursively, + # it just returns a generator object. So we must iterate over it. + for v in elements(n, (i, sxpr, ctxt)): + yield v + i += 1 + +def to_string(sxpr): + """Convert an sxpr to a string. + + sxpr sxpr + returns string + """ + io = StringIO() + show(sxpr, io) + io.seek(0) + val = io.getvalue() + io.close() + return val + +def from_string(str): + """Create an sxpr by parsing a string. + + str string + returns sxpr + """ + io = StringIO(str) + return parse(io) + +def parse(io): + """Completely parse all input from 'io'. + + io input file object + returns list of values, None if incomplete + raises ParseError on parse error + """ + pin = Parser() + while 1: + buf = io.readline() + pin.input(buf) + if len(buf) == 0: + break + if pin.ready(): + val = pin.get_all() + else: + val = None + return val + + +if __name__ == '__main__': + print ">main" + pin = Parser() + while 1: + buf = sys.stdin.read(1024) + #buf = sys.stdin.readline() + pin.input(buf) + while pin.ready(): + val = pin.get_val() + print + print '****** val=', val + if len(buf) == 0: + break + diff --git a/tools/python/xen/xm/__init__.py b/tools/python/xen/xm/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tools/python/xen/xm/create.py b/tools/python/xen/xm/create.py new file mode 100644 index 0000000000..12e2e8010c --- /dev/null +++ b/tools/python/xen/xm/create.py @@ -0,0 +1,366 @@ +# Copyright (C) 2004 Mike Wray +"""Domain creation. +""" +import string +import sys + +from xen.xend import sxp +from xen.xend import PrettyPrint +from xen.xend.XendClient import server + +from xen.xm.opts import * + +gopts = Opts(use="""[options] + +Create a domain. +""") + +gopts.opt('help', short='h', + fn=set_true, default=0, + use="Print this help.") + +gopts.opt('quiet', short='q', + fn=set_true, default=0, + use="Quiet.") + +gopts.opt('path', val='PATH', + fn=set_value, default='.:/etc/xen', + use="Search path for default scripts.") + +gopts.opt('defaults', short='f', val='FILE', + fn=set_value, default='xmdefaults', + use="Use the given default script.") + +gopts.opt('config', short='F', val='FILE', + fn=set_value, default=None, + use='Domain configuration to use (SXP).') + +gopts.opt('load', short='L', val='FILE', + fn=set_value, default=None, + use='Domain saved state to load.') + +gopts.opt('define', short='D', val='VAR=VAL', + fn=set_var, default=None, + use="""Set a variable before loading defaults, e.g. '-D vmid=3' + to set vmid. May be repeated to set more thanone variable.""") + +gopts.opt('dryrun', short='n', + fn=set_true, default=0, + use="Dry run - print the config but don't create the domain.") + +gopts.opt('name', short='N', val='NAME', + fn=set_value, default=None, + use="Domain name.") + +gopts.opt('console', short='c', + fn=set_true, default=0, + use="Connect to console after domain is created.") + +gopts.opt('kernel', short='k', val='FILE', + fn=set_value, default=None, + use="Path to kernel image.") + +gopts.opt('ramdisk', short='r', val='FILE', + fn=set_value, default='', + use="Path to ramdisk.") + +gopts.opt('builder', short='b', val='FUNCTION', + fn=set_value, default='linux', + use="Function to use to build the domain.") + +gopts.opt('memory', short='m', val='MEMORY', + fn=set_value, default=128, + use="Domain memory in MB.") + +gopts.opt('blkif', + fn=set_true, default=0, + use="Make the domain a block device backend.") + +gopts.opt('netif', + fn=set_true, default=0, + use="Make the domain a network interface backend.") + +gopts.opt('disk', short='d', val='phy:DEV,VDEV,MODE', + fn=append_value, default=[], + use="""Add a disk device to a domain. The physical device is DEV, which + is exported to the domain as VDEV. The disk is read-only if MODE + is 'r', read-write if MODE is 'w'. + The option may be repeated to add more than one disk. + """) + +gopts.opt('pci', val='BUS,DEV,FUNC', + fn=append_value, default=[], + use="""Add a PCI device to a domain, using given params (in hex). + For example '-pci c0,02,1a'. + The option may be repeated to add more than one pci device. + """) + +gopts.opt('ipaddr', short='i', val="IPADDR", + fn=append_value, default=[], + use="Add an IP address to the domain.") + +gopts.opt('vif', val="mac=MAC,bridge=BRIDGE", + fn=append_value, default=[], + use="""Add a network interface with the given MAC address and bridge. + If mac is not specified a random MAC address is used. + If bridge is not specified the default bridge is used. + This option may be repeated to add more than one vif. + Specifying vifs will increase the number of interfaces as needed. + """) + +gopts.opt('nics', val="NUM", + fn=set_int, default=1, + use="""Set the number of network interfaces. + Use the vif option to define interface parameters, otherwise + defaults are used. Specifying vifs will increase the + number of interfaces as needed. + """) + +gopts.opt('root', short='R', val='DEVICE', + fn=set_value, default='', + use="""Set the root= parameter on the kernel command line. + Use a device, e.g. /dev/sda1, or /dev/nfs for NFS root.""") + +gopts.opt('extra', short='E', val="ARGS", + fn=set_value, default='', + use="Set extra arguments to append to the kernel command line.") + +gopts.opt('ip', short='I', val='IPADDR', + fn=set_value, default='', + use="Set the kernel IP interface address.") + +gopts.opt('gateway', val="IPADDR", + fn=set_value, default='', + use="Set the kernel IP gateway.") + +gopts.opt('netmask', val="MASK", + fn=set_value, default = '', + use="Set the kernel IP netmask.") + +gopts.opt('hostname', val="NAME", + fn=set_value, default='', + use="Set the kernel IP hostname.") + +gopts.opt('interface', val="INTF", + fn=set_value, default="eth0", + use="Set the kernel IP interface name.") + +gopts.opt('dhcp', val="off|dhcp", + fn=set_value, default='off', + use="Set the kernel dhcp option.") + +gopts.opt('nfs_server', val="IPADDR", + fn=set_value, default=None, + use="Set the address of the NFS server for NFS root.") + +gopts.opt('nfs_root', val="PATH", + fn=set_value, default=None, + use="Set the path of the root NFS directory.") + +def strip(pre, s): + """Strip prefix 'pre' if present. + """ + if s.startswith(pre): + return s[len(pre):] + else: + return s + +def configure_image(config, opts): + """Create the image config. + """ + config_image = [ opts.builder ] + config_image.append([ 'kernel', os.path.abspath(opts.kernel) ]) + if opts.ramdisk: + config_image.append([ 'ramdisk', os.path.abspath(opts.ramdisk) ]) + if opts.cmdline_ip: + cmdline_ip = strip('ip=', opts.cmdline_ip) + config_image.append(['ip', cmdline_ip]) + if opts.root: + cmdline_root = strip('root=', opts.root) + config_image.append(['root', cmdline_root]) + if opts.extra: + config_image.append(['args', opts.extra]) + config.append(['image', config_image ]) + +def configure_disks(config_devs, opts): + """Create the config for disks (virtual block devices). + """ + for (uname, dev, mode) in opts.disk: + config_vbd = ['vbd', + ['uname', uname], + ['dev', dev ], + ['mode', mode ] ] + config_devs.append(['device', config_vbd]) + +def configure_pci(config_devs, opts): + """Create the config for pci devices. + """ + for (bus, dev, func) in opts.pci: + config_pci = ['pci', ['bus', bus], ['dev', dev], ['func', func]] + config_devs.append(['device', config_pci]) + +def configure_vifs(config_devs, opts): + """Create the config for virtual network interfaces. + """ + vifs = opts.vif + vifs_n = max(opts.nics, len(vifs)) + + for idx in range(0, vifs_n): + if idx < len(vifs): + d = vifs[idx] + mac = d.get('mac') + bridge = d.get('bridge') + else: + mac = None + bridge = None + config_vif = ['vif'] + if mac: + config_vif.append(['mac', mac]) + if bridge: + config_vif.append(['bridge', bridge]) + config_devs.append(['device', config_vif]) + +def configure_vfr(config, opts): + if not opts.ipaddr: return + config_vfr = ['vfr'] + idx = 0 # No way of saying which IP is for which vif? + for ip in opts.ipaddr: + config_vfr.append(['vif', ['id', idx], ['ip', ip]]) + config.append(config_vfr) + + +def make_config(opts): + """Create the domain configuration. + """ + + config = ['vm', + ['name', opts.name ], + ['memory', opts.memory ] ] + if opts.cpu: + config.append(['cpu', opts.cpu]) + if opts.blkif: + config.append(['backend', ['blkif']]) + if opts.netif: + config.append(['backend', ['netif']]) + + configure_image(config, opts) + config_devs = [] + configure_disks(config_devs, opts) + configure_pci(config_devs, opts) + configure_vifs(config_devs, opts) + config += config_devs + return config + +def preprocess_disk(opts): + if not opts.disk: return + disk = [] + for v in opts.disk: + d = v.split(',') + if len(d) != 3: + opts.err('Invalid disk specifier: ' + v) + disk.append(d) + opts.disk = disk + +def preprocess_pci(opts): + if not opts.pci: return + pci = [] + for v in opts.pci: + d = v.split(',') + if len(d) != 3: + opts.err('Invalid pci specifier: ' + v) + # Components are in hex: add hex specifier. + hexd = map(lambda v: '0x'+v, d) + pci.append(hexd) + opts.pci = pci + +def preprocess_vifs(opts): + if not opts.vif: return + vifs = [] + for vif in opts.vif: + d = {} + a = vif.split(',') + for b in a: + (k, v) = b.strip().split('=') + k = k.strip() + v = v.strip() + if k not in ['mac', 'bridge']: + opts.err('Invalid vif specifier: ' + vif) + d[k] = v + vifs.append(d) + opts.vif = vifs + +def preprocess_ip(opts): + setip = (opts.hostname or opts.netmask + or opts.gateway or opts.dhcp or opts.interface) + if not setip: return + #if not opts + ip = (opts.ip + + ':' + + ':' + opts.gateway + + ':' + opts.netmask + + ':' + opts.hostname + + ':' + opts.interface + + ':' + opts.dhcp) + opts.cmdline_ip = ip + +def preprocess_nfs(opts): + if (opts.nfs_root or opts.nfs_server): + if (not opts.nfs_root) or (not opts.nfs_server): + opts.err('Must set nfs root and nfs server') + else: + return + nfs = 'nfsroot=' + opts.nfs_server + ':' + opts.nfs_root + opts.extra = nfs + ' ' + opts.extra + +def preprocess(opts): + if not opts.kernel: + opts.err("No kernel specified") + preprocess_disk(opts) + preprocess_pci(opts) + preprocess_vifs(opts) + preprocess_ip(opts) + preprocess_nfs(opts) + +def make_domain(opts, config): + """Create, build and start a domain. + Returns: [int] the ID of the new domain. + """ + if opts.vals.load: + filename = os.path.abspath(opts.vals.load) + dominfo = server.xend_domain_restore(filename, config) + else: + dominfo = server.xend_domain_create(config) + + dom = int(sxp.child_value(dominfo, 'id')) + console_info = sxp.child(dominfo, 'console') + if console_info: + console_port = int(sxp.child_value(console_info, 'port')) + else: + console_port = None + + if server.xend_domain_unpause(dom) < 0: + server.xend_domain_destroy(dom) + opts.err("Failed to start domain %d" % dom) + opts.info("Started domain %d, console on port %d" + % (dom, console_port)) + return (dom, console_port) + +def main(argv): + opts = gopts + args = opts.parse(argv) + if opts.vals.help: + opts.usage() + return + if opts.vals.config: + pass + else: + opts.load_defaults() + preprocess(opts.vals) + config = make_config(opts.vals) + if opts.vals.dryrun: + PrettyPrint.prettyprint(config) + else: + make_domain(opts, config) + +if __name__ == '__main__': + main(sys.argv) diff --git a/tools/python/xen/xm/main.py b/tools/python/xen/xm/main.py new file mode 100644 index 0000000000..3ab5d23cf7 --- /dev/null +++ b/tools/python/xen/xm/main.py @@ -0,0 +1,448 @@ +# Copyright (C) 2004 Mike Wray +"""Grand unified management application for Xen. +""" +import os +import os.path +import sys +from getopt import getopt + +from xen.xend import PrettyPrint +from xen.xend import sxp +from xen.xend.XendClient import server +from xen.xm import create, shutdown + +class Prog: + """Base class for sub-programs. + """ + + """Program group it belongs to""" + group = 'all' + """Program name.""" + name = '??' + """Short program info.""" + info = '' + + def __init__(self, xm): + self.xm = xm + + def err(self, msg): + self.xm.err(msg) + + def help(self, args): + self.shortHelp(args) + + def shortHelp(self, args): + print "%-14s %s" % (self.name, self.info) + + def main(self, args): + """Program main entry point. + """ + pass + + +class ProgUnknown(Prog): + + name = 'unknown' + info = '' + + def help(self, args): + self.xm.err("Unknown command: %s\nTry '%s help' for more information." + % (args[0], self.xm.name)) + + main = help + +class Xm: + """Main application. + """ + + def __init__(self): + self.name = 'xm' + self.unknown = ProgUnknown(self) + self.progs = {} + + def err(self, msg): + print >>sys.stderr, "Error:", msg + sys.exit(1) + + def main(self, args): + """Main entry point. Dispatches to the progs. + """ + self.name = args[0] + if len(args) < 2: + self.err("Missing command\nTry '%s help' for more information." + % self.name) + help = self.helparg(args) + p = self.getprog(args[1], self.unknown) + if help: + p.help(args[1:]) + else: + p.main(args[1:]) + + def helparg(self, args): + for a in args: + if a in ['-h', '--help']: + return 1 + return 0 + + def prog(self, pklass): + """Add a sub-program. + + pklass program class (Prog subclass) + """ + p = pklass(self) + self.progs[p.name] = p + return p + + def getprog(self, name, val=None): + """Get a sub-program. + """ + return self.progs.get(name, val) + + def proglist(self): + """Get a list of sub-programs, ordered by group. + """ + groups = {} + for p in self.progs.values(): + l = groups.get(p.group, []) + l.append(p) + groups[p.group] = l + kl = groups.keys() + kl.sort() + pl = [] + for k in kl: + l = groups[k] + l.sort() + pl += l + return pl + +# Create the application object, then add the sub-program classes. +xm = Xm() + +class ProgHelp(Prog): + + name = "help" + info = "Print help." + + def help(self, args): + if len(args) == 2: + name = args[1] + p = self.xm.getprog(name) + if p: + p.help(args[1:]) + else: + print '%s: Unknown command: %s' % (self.name, name) + else: + for p in self.xm.proglist(): + p.shortHelp(args) + print "\nTry '%s help CMD' for help on CMD" % self.xm.name + + main = help + +xm.prog(ProgHelp) + +class ProgCreate(Prog): + + group = 'domain' + name = "create" + info = """Create a domain.""" + + def help(self, args): + create.main([args[0], '-h']) + + def main(self, args): + create.main(args) + +xm.prog(ProgCreate) + +class ProgSave(Prog): + group = 'domain' + name = "save" + info = """Save domain state (and config) to file.""" + + def help(self, args): + print args[0], "DOM FILE" + print """\nSave domain with id DOM to FILE.""" + + def main(self, args): + if len(args) < 3: self.err("%s: Missing arguments" % args[0]) + dom = args[1] + savefile = os.path.abspath(args[2]) + server.xend_domain_save(dom, savefile) + +xm.prog(ProgSave) + +class ProgRestore(Prog): + group = 'domain' + name = "restore" + info = """Create a domain from a saved state.""" + + def help(self, args): + print args[0], "FILE [CONFIG]" + print "\nRestore a domain from FILE using configuration CONFIG." + + def main(self, help, args): + if len(args) < 2: self.err("%s: Missing arguments" % args[0]) + savefile = os.path.abspath(args[1]) + if len(args) >= 3: + configfile = os.path.abspath(args[2]) + else: + configfile = None + info = server.xend_domain_restore(savefile, configfile) + PrettyPrint.prettyprint(info) + +xm.prog(ProgRestore) + +class ProgList(Prog): + group = 'domain' + name = "list" + info = """List info about domains.""" + + short_options = 'l' + long_options = ['long'] + + def help(self, args): + if help: + print args[0], '[options] [DOM...]' + print """\nGet information about domains. + Either all domains or the domains given. + + -l, --long Get more detailed information. + """ + return + + def main(self, args): + use_long = 0 + (options, params) = getopt(args[1:], + self.short_options, + self.long_options) + n = len(params) + for (k, v) in options: + if k in ['-l', '--long']: + use_long = 1 + + if n == 0: + doms = map(int, server.xend_domains()) + doms.sort() + else: + doms = map(int, params) + + if use_long: + self.long_list(doms) + else: + self.brief_list(doms) + + def brief_list(self, doms): + print 'Dom Name Mem(MB) CPU State Time(s)' + for dom in doms: + info = server.xend_domain(dom) + d = {} + d['dom'] = int(dom) + d['name'] = sxp.child_value(info, 'name', '??') + d['mem'] = int(sxp.child_value(info, 'memory', '0')) + d['cpu'] = int(sxp.child_value(info, 'cpu', '0')) + d['state'] = sxp.child_value(info, 'state', '??') + d['cpu_time'] = float(sxp.child_value(info, 'cpu_time', '0')) + print ("%(dom)-4d %(name)-16s %(mem)7d %(cpu)3d %(state)5s %(cpu_time)7.1f" % d) + + def long_list(self, doms): + for dom in doms: + info = server.xend_domain(dom) + print '\nDomain %d' % dom + PrettyPrint.prettyprint(info) + +xm.prog(ProgList) + +class ProgDestroy(Prog): + group = 'domain' + name = "destroy" + info = """Terminate a domain immediately.""" + + def help(self, args): + print args[0], 'DOM' + print '\nTerminate domain DOM immediately.' + + def main(self, args): + if len(args) < 2: self.err("%s: Missing domain" % args[0]) + dom = args[1] + server.xend_domain_destroy(dom) + +xm.prog(ProgDestroy) + +class ProgShutdown(Prog): + group = 'domain' + name = "shutdown" + info = """Shutdown a domain.""" + + def help(self, args): + shutdown.main([args[0], '-h']) + + def main(self, args): + shutdown.main(args) + +xm.prog(ProgShutdown) + +class ProgPause(Prog): + group = 'domain' + name = "pause" + info = """Pause execution of a domain.""" + + def help(self, args): + print args[0], 'DOM' + print '\nPause execution of domain DOM.' + + def main(self, args): + if len(args) < 2: self.err("%s: Missing domain" % args[0]) + dom = args[1] + server.xend_domain_pause(dom) + +xm.prog(ProgPause) + +class ProgUnpause(Prog): + group = 'domain' + name = "unpause" + info = """Unpause a paused domain.""" + + def help(self, args): + print args[0], 'DOM' + print '\nUnpause execution of domain DOM.' + + def main(self, args): + if len(args) < 2: self.err("%s: Missing domain" % args[0]) + dom = args[1] + server.xend_domain_unpause(dom) + +xm.prog(ProgUnpause) + +class ProgPincpu(Prog): + group = 'domain' + name = "pincpu" + info = """Pin a domain to a cpu. """ + + def help(self, args): + print args[0],'DOM CPU' + print '\nPin domain DOM to cpu CPU.' + + def main(self, args): + if len(args) != 3: self.err("%s: Invalid argument(s)" % args[0]) + v = map(int, args[1:3]) + server.xend_domain_pincpu(*v) + +xm.prog(ProgPincpu) + +class ProgBvt(Prog): + group = 'scheduler' + name = "bvt" + info = """Set BVT scheduler parameters.""" + + def help(self, args): + print args[0], "DOM MCUADV WARP WARPL WARPU" + print '\nSet Borrowed Virtual Time scheduler parameters.' + + def main(self, args): + if len(args) != 6: self.err("%s: Invalid argument(s)" % args[0]) + v = map(int, args[1:6]) + server.xend_domain_cpu_bvt_set(*v) + +xm.prog(ProgBvt) + +class ProgBvtslice(Prog): + group = 'scheduler' + name = "bvtslice" + info = """Set the BVT scheduler slice.""" + + def help(self, args): + print args[0], 'SLICE' + print '\nSet Borrowed Virtual Time scheduler slice.' + + def main(self, args): + if len(args) < 2: self.err('%s: Missing slice' % args[0]) + server.xend_node_cpu_bvt_slice_set(slice) + +xm.prog(ProgBvtslice) + +class ProgAtropos(Prog): + group = 'scheduler' + name= "atropos" + info = """Set atropos parameters.""" + + def help(self, args): + print args[0], "DOM PERIOD SLICE LATENCY XTRATIME" + print "\nSet atropos parameters." + + def main(self, args): + if len(args) != 5: self.err("%s: Invalid argument(s)" % args[0]) + v = map(int, args[1:5]) + server.xend_domain_cpu_atropos_set(*v) + +xm.prog(ProgAtropos) + +class ProgRrobin(Prog): + group = 'scheduler' + name = "rrobin" + info = """Set round robin slice.""" + + def help(self, args): + print args[0], "SLICE" + print "\nSet round robin scheduler slice." + + def main(self, args): + if len(args) != 2: self.err("%s: Invalid argument(s)" % args[0]) + rrslice = int(args[1]) + server.xend_node_rrobin_set(rrslice) + +xm.prog(ProgRrobin) + +class ProgInfo(Prog): + group = 'host' + name = "info" + info = """Get information about the xen host.""" + + def main(self, args): + info = server.xend_node() + for x in info[1:]: + print "%-23s:" % x[0], x[1] + +xm.prog(ProgInfo) + +class ProgConsoles(Prog): + group = 'console' + name = "consoles" + info = """Get information about domain consoles.""" + + def main(self, args): + l = server.xend_consoles() + print "Dom Port Id" + for x in l: + info = server.xend_console(x) + d = {} + d['dom'] = sxp.child(info, 'dst', ['dst', '?', '?'])[1] + d['port'] = sxp.child_value(info, 'port', '?') + d['id'] = sxp.child_value(info, 'id', '?') + print "%(dom)3s %(port)4s %(id)3s" % d + +xm.prog(ProgConsoles) + +class ProgConsole(Prog): + group = 'console' + name = "console" + info = """Open a console to a domain.""" + + def help(self, args): + print "console DOM" + print "\nOpen a console to domain DOM." + + def main(self, args): + if len(args) < 2: self.err("%s: Missing domain" % args[0]) + dom = args[1] + info = server.xend_domain(dom) + console = sxp.child(info, "console") + if not console: + self.err("No console information") + port = sxp.child_value(console, "port") + from xen.util import console_client + console_client.connect("localhost", int(port)) + +xm.prog(ProgConsole) + +def main(args): + xm.main(args) diff --git a/tools/python/xen/xm/opts.py b/tools/python/xen/xm/opts.py new file mode 100644 index 0000000000..eb07936f1e --- /dev/null +++ b/tools/python/xen/xm/opts.py @@ -0,0 +1,340 @@ +# Copyright (C) 2004 Mike Wray +"""Object-oriented command-line option support. +""" +from getopt import getopt +import os +import os.path +import sys +import types + +class Opt: + """An individual option. + """ + def __init__(self, opts, name, short=None, long=None, + val=None, fn=None, use=None, default=None): + """Create an option. + + opts parent options object + name name of the field it controls + short short (1-char) command line switch (optional) + long long command-line switch. Defaults to option name. + val string used to print option args in help. + If val is not specified the option has no arg. + fn function to call when the option is specified. + use usage (help) string + default default value if not specified on command-line + """ + self.opts = opts + self.name = name + self.short = short + if long is None: + long = name + self.long = long + self.val = val + self.use = use + self.default = default + self.optkeys = [] + if self.short: + self.optkeys.append('-' + self.short) + if self.long: + self.optkeys.append('--' + self.long) + self.fn = fn + self.specified_opt = None + self.specified_val = None + self.value = None + self.set(default) + + def __repr__(self): + return self.name + '=' + str(self.specified_val) + + __str__ = __repr__ + + def set(self, value): + """Set the option value. + """ + self.opts.setopt(self.name, value) + + def get(self): + """Get the option value. + """ + return self.opts.getopt(self.name) + + def append(self, value): + """Append a value to the option value. + """ + v = self.get() or [] + v.append(value) + self.set(v) + + def short_opt(self): + """Short option spec. + """ + if self.short: + if self.val: + return self.short + ':' + else: + return self.short + else: + return None + + def long_opt(self): + """Long option spec. + """ + if self.long: + if self.val: + return self.long + '=' + else: + return self.long + else: + return None + + def show(self): + sep = '' + for x in self.optkeys: + print sep, x, + sep = ',' + if self.val: + print self.val, + print + if self.use: + print '\t', + print self.use + if self.val: + print '\tDefault', self.default or 'None' + + def specify(self, k, v): + """Specify the option. Called when the option is set + from the command line. + + k option switch used + v optional value given (if any) + """ + if k in self.optkeys: + if self.val is None and v: + self.opts.err("Option '%s' does not take a value" % k) + self.specified_opt = k + self.specified_val = v + if self.fn: + self.fn(self, k, v) + return 1 + else: + return 0 + + def specified(self): + """Test whether the option has been specified: set + from the command line. + """ + return self.specified_opt + +class OptVals: + """Class to hold option values. + """ + pass + +class Opts: + """Container for options. + """ + def __init__(self, use=None): + """Options constructor. + + use usage string + """ + self.use = use + # List of options. + self.options = [] + # Options indexed by name. + self.options_map = {} + # Command-line arguments. + self.argv = [] + # Option values. + self.vals = OptVals() + self.vals.quiet = 0 + # Variables for default scripts. + self.vars = {} + + def __repr__(self): + return '\n'.join(map(str, self.options)) + + __str__ = __repr__ + + def opt(self, name, **args): + """Add an option. + + name option name + **args keyword params for option constructor + """ + x = Opt(self, name, **args) + self.options.append(x) + self.options_map[name] = x + return x + + def setvar(self, var, val): + """Set a default script variable. + """ + self.vars[var] = val + + def getvar(self, var): + """Get a default script variable. + """ + return self.vars.get(var) + + def option(self, name): + """Get an option (object). + """ + return self.options_map.get(name) + + def setopt(self, name, val): + """Set an option value. + An option can also be set using 'opts.vals.name = val'. + """ + setattr(self.vals, name, val) + + def getopt(self, name): + """Get an option value. + An option value can also be got using 'opts.vals.name'. + """ + getattr(self.vals, name) + + def specified(self, name): + """Test if an option has been specified. + """ + opt = self.option(name) + return opt and opt.specified() + + def err(self, msg): + """Print an error to stderr and exit. + """ + print >>sys.stderr, "Error:", msg + sys.exit(1) + + def info(self, msg): + """Print a message to stdout (unless quiet is set). + """ + if self.vals.quiet: return + print msg + + def warn(self, msg): + """Print a warning to stdout. + """ + print >>sys.stderr, "Warning:", msg + + def parse(self, argv): + """Parse arguments argv using the options. + + return remaining arguments + """ + self.argv = argv + (vals, args) = getopt(argv[1:], self.short_opts(), self.long_opts()) + self.args = args + for (k, v) in vals: + for opt in self.options: + if opt.specify(k, v): break + else: + print >>sys.stderr, "Error: Unknown option:", k + self.usage() + return args + + def short_opts(self): + """Get short options specifier for getopt. + """ + l = [] + for x in self.options: + y = x.short_opt() + if not y: continue + l.append(y) + return ''.join(l) + + def long_opts(self): + """Get long options specifier for getopt. + """ + l = [] + for x in self.options: + y = x.long_opt() + if not y: continue + l.append(y) + return l + + def usage(self): + print 'Usage: ', self.argv[0], self.use or 'OPTIONS' + for opt in self.options: + opt.show() + + def load_defaults(self): + """Load a defaults script. Assumes these options set: + 'path' search path + 'default' script name + """ + for x in [ '' ] + self.vals.path.split(':'): + if x: + p = os.path.join(x, self.vals.defaults) + else: + p = self.vals.defaults + if os.path.exists(p): + self.load(p) + break + else: + self.err("Cannot open defaults file %s" % self.vals.defaults) + + def load(self, defaults, help=0): + """Load a defaults file. Local variables in the file + are used to set options with the same names. + Variables are not used to set options that are already specified. + """ + # Create global and lobal dicts for the file. + # Initialize locals to the vars. + # Use exec to do the standard imports and + # define variables we are passing to the script. + globals = {} + locals = {} + locals.update(self.vars) + cmd = '\n'.join(["import sys", + "import os", + "import os.path", + "import xen.util.ip", + "xm_file = '%s'" % defaults, + "xm_help = %d" % help ]) + exec cmd in globals, locals + execfile(defaults, globals, locals) + if help: return + # Extract the values set by the script and set the corresponding + # options, if not set on the command line. + vtypes = [ types.StringType, + types.ListType, + types.IntType, + types.FloatType + ] + for (k, v) in locals.items(): + if self.specified(k): continue + if not(type(v) in vtypes): continue + self.setopt(k, v) + +def set_true(opt, k, v): + """Set an option true.""" + opt.set(1) + +def set_false(opt, k, v): + """Set an option false.""" + opt.set(0) + +def set_value(opt, k, v): + """Set an option to a valoue.""" + opt.set(v) + +def set_int(opt, k, v): + """Set an option to an integer value.""" + try: + v = int(v) + except: + opt.opts.err('Invalid value: ' + str(v)) + opt.set(v) + +def append_value(opt, k, v): + """Append a value to a list option.""" + opt.append(v) + +def set_var(opt, k, v): + """Set a default script variable. + """ + (var, val) = v.strip().split('=') + opt.opts.setvar(var.strip(), val.strip()) + diff --git a/tools/python/xen/xm/shutdown.py b/tools/python/xen/xm/shutdown.py new file mode 100644 index 0000000000..aaa354554a --- /dev/null +++ b/tools/python/xen/xm/shutdown.py @@ -0,0 +1,75 @@ +# Copyright (C) 2004 Mike Wray +"""Domain shutdown. +""" +import string +import sys +import time + +from xen.xend.XendClient import server +from xen.xm.opts import * + +gopts = Opts(use="""[options] [DOM] + +Shutdown one or more domains gracefully.""") + +gopts.opt('help', short='h', + fn=set_true, default=0, + use="Print this help.") + +gopts.opt('all', short='a', + fn=set_true, default=0, + use="Shutdown all domains.") + +gopts.opt('wait', short='w', + fn=set_true, default=0, + use='Wait for shutdown to complete.') + +gopts.opt('norestart', short='n', + fn=set_true, default=0, + use='Prevent domain restart.') + +def shutdown(opts, doms, wait): + def domains(): + return [ int(a) for a in server.xend_domains() ] + if doms == None: doms = domains() + if 0 in doms: + doms.remove(0) + for d in doms: + server.xend_domain_shutdown(d) + if wait: + while doms: + alive = domains() + dead = [] + for d in doms: + if d in alive: continue + dead.append(d) + for d in dead: + opts.info("Domain %d terminated" % d) + doms.remove(d) + time.sleep(1) + opts.info("All domains terminated") + +def main_all(opts, args): + shutdown(opts, None, opts.vals.wait) + +def main_dom(opts, args): + if len(args) < 1: opts.err('Missing domain') + dom = args[0] + try: + domid = int(dom) + except: + opts.err('Invalid domain: ' + dom) + shutdown(opts, [ domid ], opts.vals.wait) + +def main(argv): + opts = gopts + args = opts.parse(argv) + if opts.vals.help: + opts.usage() + return + print 'shutdown.main>', len(args), args + if opts.vals.all: + main_all(opts, args) + else: + main_dom(opts, args) + diff --git a/tools/xc/Makefile b/tools/xc/Makefile deleted file mode 100644 index 04b0e35fe1..0000000000 --- a/tools/xc/Makefile +++ /dev/null @@ -1,12 +0,0 @@ - -all: - $(MAKE) -C lib - $(MAKE) -C py - -install: all - $(MAKE) -C lib install - $(MAKE) -C py install - -clean: - $(MAKE) -C lib clean - $(MAKE) -C py clean diff --git a/tools/xc/lib/Makefile b/tools/xc/lib/Makefile deleted file mode 100644 index e1fa8dd504..0000000000 --- a/tools/xc/lib/Makefile +++ /dev/null @@ -1,118 +0,0 @@ - -MAJOR = 1.3 -MINOR = 0 -SONAME = libxc.so.$(MAJOR) - -CC = gcc - -XEN_ROOT = ../../.. - -vpath %.h $(XEN_ROOT)/xen/include/hypervisor-ifs -INCLUDES += -I $(XEN_ROOT)/xen/include/hypervisor-ifs - -vpath %.h $(XEN_ROOT)/tools/xu/lib -INCLUDES += -I $(XEN_ROOT)/tools/xu/lib - -vpath %h $(XEN_ROOT)/linux-xen-sparse/include -INCLUDES += -I $(XEN_ROOT)/linux-xen-sparse/include - -vpath %c $(XEN_ROOT)/tools/lib -INCLUDES += -I $(XEN_ROOT)/tools/lib - -LIB_SRCS := -LIB_SRCS += allocate.c -#LIB_SRCS += enum.c -LIB_SRCS += file_stream.c -LIB_SRCS += gzip_stream.c -#LIB_SRCS += hash_table.c -LIB_SRCS += iostream.c -#LIB_SRCS += kernel_stream.c -#LIB_SRCS += lexis.c -#LIB_SRCS += lzi_stream.c -#LIB_SRCS += lzo_stream.c -#LIB_SRCS += marshal.c -#LIB_SRCS += socket_stream.c -#LIB_SRCS += string_stream.c -#LIB_SRCS += sxpr.c -#LIB_SRCS += sxpr_parser.c -LIB_SRCS += sys_net.c -LIB_SRCS += sys_string.c -#LIB_SRCS += xdr.c - -SRCS := -SRCS += xc_atropos.c -SRCS += xc_bvtsched.c -SRCS += xc_domain.c -SRCS += xc_evtchn.c -SRCS += xc_io.c -SRCS += xc_linux_build.c -SRCS += xc_linux_restore.c -SRCS += xc_linux_save.c -SRCS += xc_misc.c -SRCS += xc_netbsd_build.c -SRCS += xc_physdev.c -SRCS += xc_private.c -SRCS += xc_rrobin.c - -SRCS += $(LIB_SRCS) - -#CFLAGS += -I../../../xen/include/hypervisor-ifs -#CFLAGS += -I../../xu/lib -#CFLAGS += -I../../../linux-xen-sparse/include - -CFLAGS += -Wall -CFLAGS += -Werror -CFLAGS += -g -CFLAGS += -O3 -CFLAGS += -fno-strict-aliasing -CFLAGS += $(INCLUDES) -# Get gcc to generate the dependencies for us. -CFLAGS += -Wp,-MD,.$(@F).d -DEPS = .*.d - -OBJS = $(patsubst %.c,%.o,$(SRCS)) - -LIB = libxc.so libxc.so.$(MAJOR) libxc.so.$(MAJOR).$(MINOR) - -all: check-for-zlib $(LIB) - -check-for-zlib: - @if [ ! -e /usr/include/zlib.h ]; then \ - echo "***********************************************************"; \ - echo "ERROR: install zlib header files (http://www.gzip.org/zlib)"; \ - echo "***********************************************************"; \ - false; \ - fi - -install: all - mkdir -p $(prefix)/usr/lib - mkdir -p $(prefix)/usr/include - install -m0755 $(LIB) $(prefix)/usr/lib - install -m0644 xc.h $(prefix)/usr/include - -clean: - $(RM) *.a *.so *.o *.rpm $(LIB) - $(RM) *~ - $(RM) $(DEPS) - -rpm: all - rm -rf staging - mkdir staging - mkdir staging/i386 - rpmbuild --define "staging$$PWD/staging" --define '_builddir.' \ - --define "_rpmdir$$PWD/staging" -bb rpm.spec - mv staging/i386/*.rpm . - rm -rf staging - -libxc.so: - ln -sf libxc.so.$(MAJOR) $@ -libxc.so.$(MAJOR): - ln -sf libxc.so.$(MAJOR).$(MINOR) $@ -libxc.so.$(MAJOR).$(MINOR): $(OBJS) - $(CC) -Wl,-soname -Wl,$(SONAME) -shared -o $@ $^ -lz - -%.o: %.c Makefile - -# $(CC) $(CFLAGS) -o $@ $< - --include $(DEPS) diff --git a/tools/xc/lib/rpm.spec b/tools/xc/lib/rpm.spec deleted file mode 100644 index 1b4c5fc85a..0000000000 --- a/tools/xc/lib/rpm.spec +++ /dev/null @@ -1,28 +0,0 @@ -Summary: Xen control interface library -Name: xen-internal-library -Version: 1.2 -Release: 1 -License: Xen -Group: Xen -BuildRoot: %{staging} -%description -Library to make it easier to access the Xen control interfaces. - -%pre -%preun -%install -install -m 0755 -d $RPM_BUILD_ROOT/lib -install -m 0755 libxc.a $RPM_BUILD_ROOT/lib/libxc.a -install -m 0755 libxc.so $RPM_BUILD_ROOT/lib/libxc.so -install -m 0755 -d $RPM_BUILD_ROOT/include -install -m 0644 xc.h $RPM_BUILD_ROOT/include/xc.h -%clean -%post -%postun -%files -%defattr(-,root,root) -%dir /lib -/lib/libxc.a -/lib/libxc.so -%dir /include -/include/xc.h diff --git a/tools/xc/lib/xc.h b/tools/xc/lib/xc.h deleted file mode 100644 index f9692607bd..0000000000 --- a/tools/xc/lib/xc.h +++ /dev/null @@ -1,203 +0,0 @@ -/****************************************************************************** - * xc.h - * - * A library for low-level access to the Xen control interfaces. - * - * Copyright (c) 2003, K A Fraser. - */ - -#ifndef __XC_H__ -#define __XC_H__ - -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned long u32; -typedef unsigned long long u64; -typedef signed char s8; -typedef signed short s16; -typedef signed long s32; -typedef signed long long s64; - -/* Obtain or relinquish a handle on the 'xc' library. */ -int xc_interface_open(void); -int xc_interface_close(int xc_handle); - -typedef struct { - u32 domid; - unsigned int cpu; - unsigned int dying:1, crashed:1, shutdown:1, - paused:1, blocked:1, running:1; - unsigned int shutdown_reason; /* only meaningful if shutdown==1 */ - unsigned long nr_pages; - unsigned long shared_info_frame; - u64 cpu_time; -#define XC_DOMINFO_MAXNAME 16 - char name[XC_DOMINFO_MAXNAME]; - unsigned long max_memkb; -} xc_dominfo_t; - -typedef struct xc_shadow_control_stats_st -{ - unsigned long fault_count; - unsigned long dirty_count; - unsigned long dirty_net_count; - unsigned long dirty_block_count; -} xc_shadow_control_stats_t; - -int xc_domain_create(int xc_handle, - unsigned int mem_kb, - const char *name, - int cpu, - u32 *pdomid); -int xc_domain_pause(int xc_handle, - u32 domid); -int xc_domain_unpause(int xc_handle, - u32 domid); -int xc_domain_destroy(int xc_handle, - u32 domid); -int xc_domain_pincpu(int xc_handle, - u32 domid, - int cpu); -int xc_domain_getinfo(int xc_handle, - u32 first_domid, - unsigned int max_doms, - xc_dominfo_t *info); - -int xc_shadow_control(int xc_handle, - u32 domid, - unsigned int sop, - unsigned long *dirty_bitmap, - unsigned long pages, - xc_shadow_control_stats_t *stats); - - -#define XCFLAGS_VERBOSE 1 -#define XCFLAGS_LIVE 2 -#define XCFLAGS_DEBUG 4 - -struct XcIOContext; -int xc_linux_save(int xc_handle, struct XcIOContext *ioctxt); -int xc_linux_restore(int xc_handle, struct XcIOContext *ioctxt); - -int xc_linux_build(int xc_handle, - u32 domid, - const char *image_name, - const char *ramdisk_name, - const char *cmdline, - unsigned int control_evtchn, - unsigned long flags); - -int xc_netbsd_build(int xc_handle, - u32 domid, - const char *image_name, - const char *cmdline, - unsigned int control_evtchn); - -int xc_bvtsched_global_set(int xc_handle, - unsigned long ctx_allow); - -int xc_bvtsched_domain_set(int xc_handle, - u32 domid, - unsigned long mcuadv, - unsigned long warp, - unsigned long warpl, - unsigned long warpu); - -int xc_bvtsched_global_get(int xc_handle, - unsigned long *ctx_allow); - -int xc_bvtsched_domain_get(int xc_handle, - u32 domid, - unsigned long *mcuadv, - unsigned long *warp, - unsigned long *warpl, - unsigned long *warpu); - -int xc_atropos_domain_set(int xc_handle, - u32 domid, - u64 period, u64 slice, u64 latency, - int xtratime); - -int xc_atropos_domain_get(int xc_handle, - u32 domid, - u64* period, u64 *slice, u64 *latency, - int *xtratime); - -int xc_rrobin_global_set(int xc_handle, u64 slice); - -int xc_rrobin_global_get(int xc_handle, u64 *slice); - -#define DOMID_SELF (0x7FFFFFFEU) - -typedef struct { -#define EVTCHNSTAT_closed 0 /* Chennel is not in use. */ -#define EVTCHNSTAT_unbound 1 /* Channel is not bound to a source. */ -#define EVTCHNSTAT_interdomain 2 /* Channel is connected to remote domain. */ -#define EVTCHNSTAT_pirq 3 /* Channel is bound to a phys IRQ line. */ -#define EVTCHNSTAT_virq 4 /* Channel is bound to a virtual IRQ line */ - int status; - union { - struct { - u32 dom; - int port; - } interdomain; - int pirq; - int virq; - } u; -} xc_evtchn_status_t; - -int xc_evtchn_bind_interdomain(int xc_handle, - u32 dom1, /* may be DOMID_SELF */ - u32 dom2, /* may be DOMID_SELF */ - int *port1, - int *port2); -int xc_evtchn_bind_virq(int xc_handle, - int virq, - int *port); -int xc_evtchn_close(int xc_handle, - u32 dom, /* may be DOMID_SELF */ - int port); -int xc_evtchn_send(int xc_handle, - int local_port); -int xc_evtchn_status(int xc_handle, - u32 dom, /* may be DOMID_SELF */ - int port, - xc_evtchn_status_t *status); - -int xc_physdev_pci_access_modify(int xc_handle, - u32 domid, - int bus, - int dev, - int func, - int enable); - -int xc_readconsolering(int xc_handle, - char *str, - unsigned int max_chars, - int clear); - -typedef struct { - int ht_per_core; - int cores; - unsigned long total_pages; - unsigned long free_pages; - unsigned long cpu_khz; -} xc_physinfo_t; - -int xc_physinfo(int xc_handle, - xc_physinfo_t *info); - -int xc_domain_setname(int xc_handle, - u32 domid, - char *name); - -int xc_domain_setinitialmem(int xc_handle, - u32 domid, - unsigned int initial_memkb); - -int xc_domain_setmaxmem(int xc_handle, - u32 domid, - unsigned int max_memkb); - - -#endif /* __XC_H__ */ diff --git a/tools/xc/lib/xc_atropos.c b/tools/xc/lib/xc_atropos.c deleted file mode 100644 index 13d07ca440..0000000000 --- a/tools/xc/lib/xc_atropos.c +++ /dev/null @@ -1,51 +0,0 @@ -/****************************************************************************** - * xc_atropos.c - * - * API for manipulating parameters of the Atropos scheduler. - * - * by Mark Williamson, Copyright (c) 2004 Intel Research Cambridge. - */ - -#include "xc_private.h" - -int xc_atropos_domain_set(int xc_handle, - u32 domid, u64 period, u64 slice, u64 latency, - int xtratime) -{ - dom0_op_t op; - struct atropos_adjdom *p = &op.u.adjustdom.u.atropos; - - op.cmd = DOM0_ADJUSTDOM; - op.u.adjustdom.domain = (domid_t)domid; - op.u.adjustdom.sched_id = SCHED_ATROPOS; - op.u.adjustdom.direction = SCHED_INFO_PUT; - - p->nat_period = period; - p->nat_slice = slice; - p->latency = latency; - p->xtratime = xtratime; - - return do_dom0_op(xc_handle, &op); -} - -int xc_atropos_domain_get(int xc_handle, u32 domid, u64 *period, - u64 *slice, u64 *latency, int *xtratime) -{ - dom0_op_t op; - int ret; - struct atropos_adjdom *p = &op.u.adjustdom.u.atropos; - - op.cmd = DOM0_ADJUSTDOM; - op.u.adjustdom.domain = (domid_t)domid; - op.u.adjustdom.sched_id = SCHED_ATROPOS; - op.u.adjustdom.direction = SCHED_INFO_GET; - - ret = do_dom0_op(xc_handle, &op); - - *period = p->nat_period; - *slice = p->nat_slice; - *latency = p->latency; - *xtratime = p->xtratime; - - return ret; -} diff --git a/tools/xc/lib/xc_bvtsched.c b/tools/xc/lib/xc_bvtsched.c deleted file mode 100644 index aeaddcfb04..0000000000 --- a/tools/xc/lib/xc_bvtsched.c +++ /dev/null @@ -1,88 +0,0 @@ -/****************************************************************************** - * xc_bvtsched.c - * - * API for manipulating parameters of the Borrowed Virtual Time scheduler. - * - * Copyright (c) 2003, K A Fraser. - */ - -#include "xc_private.h" - -int xc_bvtsched_global_set(int xc_handle, - unsigned long ctx_allow) -{ - dom0_op_t op; - - op.cmd = DOM0_SCHEDCTL; - op.u.schedctl.sched_id = SCHED_BVT; - op.u.schedctl.direction = SCHED_INFO_PUT; - op.u.schedctl.u.bvt.ctx_allow = ctx_allow; - - return do_dom0_op(xc_handle, &op); -} - -int xc_bvtsched_global_get(int xc_handle, - unsigned long *ctx_allow) -{ - dom0_op_t op; - int ret; - - op.cmd = DOM0_SCHEDCTL; - op.u.schedctl.sched_id = SCHED_BVT; - op.u.schedctl.direction = SCHED_INFO_GET; - - ret = do_dom0_op(xc_handle, &op); - - *ctx_allow = op.u.schedctl.u.bvt.ctx_allow; - - return ret; -} - -int xc_bvtsched_domain_set(int xc_handle, - u32 domid, - unsigned long mcuadv, - unsigned long warp, - unsigned long warpl, - unsigned long warpu) -{ - dom0_op_t op; - struct bvt_adjdom *bvtadj = &op.u.adjustdom.u.bvt; - - op.cmd = DOM0_ADJUSTDOM; - op.u.adjustdom.domain = (domid_t)domid; - op.u.adjustdom.sched_id = SCHED_BVT; - op.u.adjustdom.direction = SCHED_INFO_PUT; - - bvtadj->mcu_adv = mcuadv; - bvtadj->warp = warp; - bvtadj->warpl = warpl; - bvtadj->warpu = warpu; - return do_dom0_op(xc_handle, &op); -} - - -int xc_bvtsched_domain_get(int xc_handle, - u32 domid, - unsigned long *mcuadv, - unsigned long *warp, - unsigned long *warpl, - unsigned long *warpu) -{ - - dom0_op_t op; - int ret; - struct bvt_adjdom *adjptr = &op.u.adjustdom.u.bvt; - - op.cmd = DOM0_ADJUSTDOM; - op.u.adjustdom.domain = (domid_t)domid; - op.u.adjustdom.sched_id = SCHED_BVT; - op.u.adjustdom.direction = SCHED_INFO_GET; - - ret = do_dom0_op(xc_handle, &op); - - *mcuadv = adjptr->mcu_adv; - *warp = adjptr->warp; - *warpl = adjptr->warpl; - *warpu = adjptr->warpu; - return ret; -} diff --git a/tools/xc/lib/xc_domain.c b/tools/xc/lib/xc_domain.c deleted file mode 100644 index ab83d0ce7b..0000000000 --- a/tools/xc/lib/xc_domain.c +++ /dev/null @@ -1,194 +0,0 @@ -/****************************************************************************** - * xc_domain.c - * - * API for manipulating and obtaining information on domains. - * - * Copyright (c) 2003, K A Fraser. - */ - -#include "xc_private.h" - -int xc_domain_create(int xc_handle, - unsigned int mem_kb, - const char *name, - int cpu, - u32 *pdomid) -{ - int err; - dom0_op_t op; - - op.cmd = DOM0_CREATEDOMAIN; - op.u.createdomain.memory_kb = mem_kb; - strncpy(op.u.createdomain.name, name, MAX_DOMAIN_NAME); - op.u.createdomain.name[MAX_DOMAIN_NAME-1] = '\0'; - op.u.createdomain.cpu = cpu; - - if ( (err = do_dom0_op(xc_handle, &op)) == 0 ) - *pdomid = (u32)op.u.createdomain.domain; - - return err; -} - - -int xc_domain_pause(int xc_handle, - u32 domid) -{ - dom0_op_t op; - op.cmd = DOM0_PAUSEDOMAIN; - op.u.pausedomain.domain = (domid_t)domid; - return do_dom0_op(xc_handle, &op); -} - - -int xc_domain_unpause(int xc_handle, - u32 domid) -{ - dom0_op_t op; - op.cmd = DOM0_UNPAUSEDOMAIN; - op.u.unpausedomain.domain = (domid_t)domid; - return do_dom0_op(xc_handle, &op); -} - - -int xc_domain_destroy(int xc_handle, - u32 domid) -{ - dom0_op_t op; - op.cmd = DOM0_DESTROYDOMAIN; - op.u.destroydomain.domain = (domid_t)domid; - return do_dom0_op(xc_handle, &op); -} - -int xc_domain_pincpu(int xc_handle, - u32 domid, - int cpu) -{ - dom0_op_t op; - op.cmd = DOM0_PINCPUDOMAIN; - op.u.pincpudomain.domain = (domid_t)domid; - op.u.pincpudomain.cpu = cpu; - return do_dom0_op(xc_handle, &op); -} - - -int xc_domain_getinfo(int xc_handle, - u32 first_domid, - unsigned int max_doms, - xc_dominfo_t *info) -{ - unsigned int nr_doms; - u32 next_domid = first_domid; - dom0_op_t op; - - for ( nr_doms = 0; nr_doms < max_doms; nr_doms++ ) - { - op.cmd = DOM0_GETDOMAININFO; - op.u.getdomaininfo.domain = (domid_t)next_domid; - op.u.getdomaininfo.ctxt = NULL; /* no exec context info, thanks. */ - if ( do_dom0_op(xc_handle, &op) < 0 ) - break; - info->domid = (u32)op.u.getdomaininfo.domain; - - info->cpu = - (op.u.getdomaininfo.flags>>DOMFLAGS_CPUSHIFT) & DOMFLAGS_CPUMASK; - - info->dying = !!(op.u.getdomaininfo.flags & DOMFLAGS_DYING); - info->crashed = !!(op.u.getdomaininfo.flags & DOMFLAGS_CRASHED); - info->shutdown = !!(op.u.getdomaininfo.flags & DOMFLAGS_SHUTDOWN); - info->paused = !!(op.u.getdomaininfo.flags & DOMFLAGS_PAUSED); - info->blocked = !!(op.u.getdomaininfo.flags & DOMFLAGS_BLOCKED); - info->running = !!(op.u.getdomaininfo.flags & DOMFLAGS_RUNNING); - - info->shutdown_reason = - (op.u.getdomaininfo.flags>>DOMFLAGS_SHUTDOWNSHIFT) & - DOMFLAGS_SHUTDOWNMASK; - - info->nr_pages = op.u.getdomaininfo.tot_pages; - info->max_memkb = op.u.getdomaininfo.max_pages<<(PAGE_SHIFT-10); - info->shared_info_frame = op.u.getdomaininfo.shared_info_frame; - info->cpu_time = op.u.getdomaininfo.cpu_time; - strncpy(info->name, op.u.getdomaininfo.name, XC_DOMINFO_MAXNAME); - info->name[XC_DOMINFO_MAXNAME-1] = '\0'; - - next_domid = (u32)op.u.getdomaininfo.domain + 1; - info++; - } - - return nr_doms; -} - -int xc_domain_getfullinfo(int xc_handle, - u32 domid, - dom0_op_t *op, - full_execution_context_t *ctxt ) -{ - int rc; - op->cmd = DOM0_GETDOMAININFO; - op->u.getdomaininfo.domain = (domid_t)domid; - op->u.getdomaininfo.ctxt = ctxt; - - rc = do_dom0_op(xc_handle, op); - if ( ((u32)op->u.getdomaininfo.domain != domid) && rc > 0 ) - return -ESRCH; - else - return rc; -} - - -int xc_shadow_control(int xc_handle, - u32 domid, - unsigned int sop, - unsigned long *dirty_bitmap, - unsigned long pages, - xc_shadow_control_stats_t *stats ) -{ - int rc; - dom0_op_t op; - op.cmd = DOM0_SHADOW_CONTROL; - op.u.shadow_control.domain = (domid_t)domid; - op.u.shadow_control.op = sop; - op.u.shadow_control.dirty_bitmap = dirty_bitmap; - op.u.shadow_control.pages = pages; - - rc = do_dom0_op(xc_handle, &op); - - if ( stats ) - memcpy(stats, &op.u.shadow_control.stats, - sizeof(xc_shadow_control_stats_t)); - - return (rc == 0) ? op.u.shadow_control.pages : rc; -} - -int xc_domain_setname(int xc_handle, - u32 domid, - char *name) -{ - dom0_op_t op; - op.cmd = DOM0_SETDOMAINNAME; - op.u.setdomainname.domain = (domid_t)domid; - strncpy(op.u.setdomainname.name, name, MAX_DOMAIN_NAME); - return do_dom0_op(xc_handle, &op); -} - -int xc_domain_setinitialmem(int xc_handle, - u32 domid, - unsigned int initial_memkb) -{ - dom0_op_t op; - op.cmd = DOM0_SETDOMAININITIALMEM; - op.u.setdomaininitialmem.domain = (domid_t)domid; - op.u.setdomaininitialmem.initial_memkb = initial_memkb; - return do_dom0_op(xc_handle, &op); -} - -int xc_domain_setmaxmem(int xc_handle, - u32 domid, - unsigned int max_memkb) -{ - dom0_op_t op; - op.cmd = DOM0_SETDOMAINMAXMEM; - op.u.setdomainmaxmem.domain = (domid_t)domid; - op.u.setdomainmaxmem.max_memkb = max_memkb; - return do_dom0_op(xc_handle, &op); -} - diff --git a/tools/xc/lib/xc_elf.h b/tools/xc/lib/xc_elf.h deleted file mode 100644 index e0d0c26131..0000000000 --- a/tools/xc/lib/xc_elf.h +++ /dev/null @@ -1,523 +0,0 @@ -/* - * Copyright (c) 1995, 1996 Erik Theisen. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -typedef u_int8_t Elf_Byte; - -typedef u_int32_t Elf32_Addr; /* Unsigned program address */ -typedef u_int32_t Elf32_Off; /* Unsigned file offset */ -typedef int32_t Elf32_Sword; /* Signed large integer */ -typedef u_int32_t Elf32_Word; /* Unsigned large integer */ -typedef u_int16_t Elf32_Half; /* Unsigned medium integer */ - -typedef u_int64_t Elf64_Addr; -typedef u_int64_t Elf64_Off; -typedef int32_t Elf64_Shalf; - -typedef int32_t Elf64_Sword; -typedef u_int32_t Elf64_Word; - -typedef int64_t Elf64_Sxword; -typedef u_int64_t Elf64_Xword; - -typedef u_int32_t Elf64_Half; -typedef u_int16_t Elf64_Quarter; - -/* - * e_ident[] identification indexes - * See http://www.caldera.com/developers/gabi/2000-07-17/ch4.eheader.html - */ -#define EI_MAG0 0 /* file ID */ -#define EI_MAG1 1 /* file ID */ -#define EI_MAG2 2 /* file ID */ -#define EI_MAG3 3 /* file ID */ -#define EI_CLASS 4 /* file class */ -#define EI_DATA 5 /* data encoding */ -#define EI_VERSION 6 /* ELF header version */ -#define EI_OSABI 7 /* OS/ABI ID */ -#define EI_ABIVERSION 8 /* ABI version */ -#define EI_PAD 9 /* start of pad bytes */ -#define EI_NIDENT 16 /* Size of e_ident[] */ - -/* e_ident[] magic number */ -#define ELFMAG0 0x7f /* e_ident[EI_MAG0] */ -#define ELFMAG1 'E' /* e_ident[EI_MAG1] */ -#define ELFMAG2 'L' /* e_ident[EI_MAG2] */ -#define ELFMAG3 'F' /* e_ident[EI_MAG3] */ -#define ELFMAG "\177ELF" /* magic */ -#define SELFMAG 4 /* size of magic */ - -/* e_ident[] file class */ -#define ELFCLASSNONE 0 /* invalid */ -#define ELFCLASS32 1 /* 32-bit objs */ -#define ELFCLASS64 2 /* 64-bit objs */ -#define ELFCLASSNUM 3 /* number of classes */ - -/* e_ident[] data encoding */ -#define ELFDATANONE 0 /* invalid */ -#define ELFDATA2LSB 1 /* Little-Endian */ -#define ELFDATA2MSB 2 /* Big-Endian */ -#define ELFDATANUM 3 /* number of data encode defines */ - -/* e_ident[] Operating System/ABI */ -#define ELFOSABI_SYSV 0 /* UNIX System V ABI */ -#define ELFOSABI_HPUX 1 /* HP-UX operating system */ -#define ELFOSABI_NETBSD 2 /* NetBSD */ -#define ELFOSABI_LINUX 3 /* GNU/Linux */ -#define ELFOSABI_HURD 4 /* GNU/Hurd */ -#define ELFOSABI_86OPEN 5 /* 86Open common IA32 ABI */ -#define ELFOSABI_SOLARIS 6 /* Solaris */ -#define ELFOSABI_MONTEREY 7 /* Monterey */ -#define ELFOSABI_IRIX 8 /* IRIX */ -#define ELFOSABI_FREEBSD 9 /* FreeBSD */ -#define ELFOSABI_TRU64 10 /* TRU64 UNIX */ -#define ELFOSABI_MODESTO 11 /* Novell Modesto */ -#define ELFOSABI_OPENBSD 12 /* OpenBSD */ -#define ELFOSABI_ARM 97 /* ARM */ -#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ - -/* e_ident */ -#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \ - (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \ - (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \ - (ehdr).e_ident[EI_MAG3] == ELFMAG3) - -/* ELF Header */ -typedef struct elfhdr { - unsigned char e_ident[EI_NIDENT]; /* ELF Identification */ - Elf32_Half e_type; /* object file type */ - Elf32_Half e_machine; /* machine */ - Elf32_Word e_version; /* object file version */ - Elf32_Addr e_entry; /* virtual entry point */ - Elf32_Off e_phoff; /* program header table offset */ - Elf32_Off e_shoff; /* section header table offset */ - Elf32_Word e_flags; /* processor-specific flags */ - Elf32_Half e_ehsize; /* ELF header size */ - Elf32_Half e_phentsize; /* program header entry size */ - Elf32_Half e_phnum; /* number of program header entries */ - Elf32_Half e_shentsize; /* section header entry size */ - Elf32_Half e_shnum; /* number of section header entries */ - Elf32_Half e_shstrndx; /* section header table's "section - header string table" entry offset */ -} Elf32_Ehdr; - -typedef struct { - unsigned char e_ident[EI_NIDENT]; /* Id bytes */ - Elf64_Quarter e_type; /* file type */ - Elf64_Quarter e_machine; /* machine type */ - Elf64_Half e_version; /* version number */ - Elf64_Addr e_entry; /* entry point */ - Elf64_Off e_phoff; /* Program hdr offset */ - Elf64_Off e_shoff; /* Section hdr offset */ - Elf64_Half e_flags; /* Processor flags */ - Elf64_Quarter e_ehsize; /* sizeof ehdr */ - Elf64_Quarter e_phentsize; /* Program header entry size */ - Elf64_Quarter e_phnum; /* Number of program headers */ - Elf64_Quarter e_shentsize; /* Section header entry size */ - Elf64_Quarter e_shnum; /* Number of section headers */ - Elf64_Quarter e_shstrndx; /* String table index */ -} Elf64_Ehdr; - -/* e_type */ -#define ET_NONE 0 /* No file type */ -#define ET_REL 1 /* relocatable file */ -#define ET_EXEC 2 /* executable file */ -#define ET_DYN 3 /* shared object file */ -#define ET_CORE 4 /* core file */ -#define ET_NUM 5 /* number of types */ -#define ET_LOPROC 0xff00 /* reserved range for processor */ -#define ET_HIPROC 0xffff /* specific e_type */ - -/* e_machine */ -#define EM_NONE 0 /* No Machine */ -#define EM_M32 1 /* AT&T WE 32100 */ -#define EM_SPARC 2 /* SPARC */ -#define EM_386 3 /* Intel 80386 */ -#define EM_68K 4 /* Motorola 68000 */ -#define EM_88K 5 /* Motorola 88000 */ -#define EM_486 6 /* Intel 80486 - unused? */ -#define EM_860 7 /* Intel 80860 */ -#define EM_MIPS 8 /* MIPS R3000 Big-Endian only */ -/* - * Don't know if EM_MIPS_RS4_BE, - * EM_SPARC64, EM_PARISC, - * or EM_PPC are ABI compliant - */ -#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */ -#define EM_SPARC64 11 /* SPARC v9 64-bit unoffical */ -#define EM_PARISC 15 /* HPPA */ -#define EM_SPARC32PLUS 18 /* Enhanced instruction set SPARC */ -#define EM_PPC 20 /* PowerPC */ -#define EM_ARM 40 /* Advanced RISC Machines ARM */ -#define EM_ALPHA 41 /* DEC ALPHA */ -#define EM_SPARCV9 43 /* SPARC version 9 */ -#define EM_ALPHA_EXP 0x9026 /* DEC ALPHA */ -#define EM_X86_64 62 /* AMD x86-64 architecture */ -#define EM_VAX 75 /* DEC VAX */ -#define EM_NUM 15 /* number of machine types */ - -/* Version */ -#define EV_NONE 0 /* Invalid */ -#define EV_CURRENT 1 /* Current */ -#define EV_NUM 2 /* number of versions */ - -/* Section Header */ -typedef struct { - Elf32_Word sh_name; /* name - index into section header - string table section */ - Elf32_Word sh_type; /* type */ - Elf32_Word sh_flags; /* flags */ - Elf32_Addr sh_addr; /* address */ - Elf32_Off sh_offset; /* file offset */ - Elf32_Word sh_size; /* section size */ - Elf32_Word sh_link; /* section header table index link */ - Elf32_Word sh_info; /* extra information */ - Elf32_Word sh_addralign; /* address alignment */ - Elf32_Word sh_entsize; /* section entry size */ -} Elf32_Shdr; - -typedef struct { - Elf64_Half sh_name; /* section name */ - Elf64_Half sh_type; /* section type */ - Elf64_Xword sh_flags; /* section flags */ - Elf64_Addr sh_addr; /* virtual address */ - Elf64_Off sh_offset; /* file offset */ - Elf64_Xword sh_size; /* section size */ - Elf64_Half sh_link; /* link to another */ - Elf64_Half sh_info; /* misc info */ - Elf64_Xword sh_addralign; /* memory alignment */ - Elf64_Xword sh_entsize; /* table entry size */ -} Elf64_Shdr; - -/* Special Section Indexes */ -#define SHN_UNDEF 0 /* undefined */ -#define SHN_LORESERVE 0xff00 /* lower bounds of reserved indexes */ -#define SHN_LOPROC 0xff00 /* reserved range for processor */ -#define SHN_HIPROC 0xff1f /* specific section indexes */ -#define SHN_ABS 0xfff1 /* absolute value */ -#define SHN_COMMON 0xfff2 /* common symbol */ -#define SHN_HIRESERVE 0xffff /* upper bounds of reserved indexes */ - -/* sh_type */ -#define SHT_NULL 0 /* inactive */ -#define SHT_PROGBITS 1 /* program defined information */ -#define SHT_SYMTAB 2 /* symbol table section */ -#define SHT_STRTAB 3 /* string table section */ -#define SHT_RELA 4 /* relocation section with addends*/ -#define SHT_HASH 5 /* symbol hash table section */ -#define SHT_DYNAMIC 6 /* dynamic section */ -#define SHT_NOTE 7 /* note section */ -#define SHT_NOBITS 8 /* no space section */ -#define SHT_REL 9 /* relation section without addends */ -#define SHT_SHLIB 10 /* reserved - purpose unknown */ -#define SHT_DYNSYM 11 /* dynamic symbol table section */ -#define SHT_NUM 12 /* number of section types */ -#define SHT_LOPROC 0x70000000 /* reserved range for processor */ -#define SHT_HIPROC 0x7fffffff /* specific section header types */ -#define SHT_LOUSER 0x80000000 /* reserved range for application */ -#define SHT_HIUSER 0xffffffff /* specific indexes */ - -/* Section names */ -#define ELF_BSS ".bss" /* uninitialized data */ -#define ELF_DATA ".data" /* initialized data */ -#define ELF_DEBUG ".debug" /* debug */ -#define ELF_DYNAMIC ".dynamic" /* dynamic linking information */ -#define ELF_DYNSTR ".dynstr" /* dynamic string table */ -#define ELF_DYNSYM ".dynsym" /* dynamic symbol table */ -#define ELF_FINI ".fini" /* termination code */ -#define ELF_GOT ".got" /* global offset table */ -#define ELF_HASH ".hash" /* symbol hash table */ -#define ELF_INIT ".init" /* initialization code */ -#define ELF_REL_DATA ".rel.data" /* relocation data */ -#define ELF_REL_FINI ".rel.fini" /* relocation termination code */ -#define ELF_REL_INIT ".rel.init" /* relocation initialization code */ -#define ELF_REL_DYN ".rel.dyn" /* relocaltion dynamic link info */ -#define ELF_REL_RODATA ".rel.rodata" /* relocation read-only data */ -#define ELF_REL_TEXT ".rel.text" /* relocation code */ -#define ELF_RODATA ".rodata" /* read-only data */ -#define ELF_SHSTRTAB ".shstrtab" /* section header string table */ -#define ELF_STRTAB ".strtab" /* string table */ -#define ELF_SYMTAB ".symtab" /* symbol table */ -#define ELF_TEXT ".text" /* code */ - - -/* Section Attribute Flags - sh_flags */ -#define SHF_WRITE 0x1 /* Writable */ -#define SHF_ALLOC 0x2 /* occupies memory */ -#define SHF_EXECINSTR 0x4 /* executable */ -#define SHF_MASKPROC 0xf0000000 /* reserved bits for processor */ - /* specific section attributes */ - -/* Symbol Table Entry */ -typedef struct elf32_sym { - Elf32_Word st_name; /* name - index into string table */ - Elf32_Addr st_value; /* symbol value */ - Elf32_Word st_size; /* symbol size */ - unsigned char st_info; /* type and binding */ - unsigned char st_other; /* 0 - no defined meaning */ - Elf32_Half st_shndx; /* section header index */ -} Elf32_Sym; - -typedef struct { - Elf64_Half st_name; /* Symbol name index in str table */ - Elf_Byte st_info; /* type / binding attrs */ - Elf_Byte st_other; /* unused */ - Elf64_Quarter st_shndx; /* section index of symbol */ - Elf64_Xword st_value; /* value of symbol */ - Elf64_Xword st_size; /* size of symbol */ -} Elf64_Sym; - -/* Symbol table index */ -#define STN_UNDEF 0 /* undefined */ - -/* Extract symbol info - st_info */ -#define ELF32_ST_BIND(x) ((x) >> 4) -#define ELF32_ST_TYPE(x) (((unsigned int) x) & 0xf) -#define ELF32_ST_INFO(b,t) (((b) << 4) + ((t) & 0xf)) - -#define ELF64_ST_BIND(x) ((x) >> 4) -#define ELF64_ST_TYPE(x) (((unsigned int) x) & 0xf) -#define ELF64_ST_INFO(b,t) (((b) << 4) + ((t) & 0xf)) - -/* Symbol Binding - ELF32_ST_BIND - st_info */ -#define STB_LOCAL 0 /* Local symbol */ -#define STB_GLOBAL 1 /* Global symbol */ -#define STB_WEAK 2 /* like global - lower precedence */ -#define STB_NUM 3 /* number of symbol bindings */ -#define STB_LOPROC 13 /* reserved range for processor */ -#define STB_HIPROC 15 /* specific symbol bindings */ - -/* Symbol type - ELF32_ST_TYPE - st_info */ -#define STT_NOTYPE 0 /* not specified */ -#define STT_OBJECT 1 /* data object */ -#define STT_FUNC 2 /* function */ -#define STT_SECTION 3 /* section */ -#define STT_FILE 4 /* file */ -#define STT_NUM 5 /* number of symbol types */ -#define STT_LOPROC 13 /* reserved range for processor */ -#define STT_HIPROC 15 /* specific symbol types */ - -/* Relocation entry with implicit addend */ -typedef struct { - Elf32_Addr r_offset; /* offset of relocation */ - Elf32_Word r_info; /* symbol table index and type */ -} Elf32_Rel; - -/* Relocation entry with explicit addend */ -typedef struct { - Elf32_Addr r_offset; /* offset of relocation */ - Elf32_Word r_info; /* symbol table index and type */ - Elf32_Sword r_addend; -} Elf32_Rela; - -/* Extract relocation info - r_info */ -#define ELF32_R_SYM(i) ((i) >> 8) -#define ELF32_R_TYPE(i) ((unsigned char) (i)) -#define ELF32_R_INFO(s,t) (((s) << 8) + (unsigned char)(t)) - -typedef struct { - Elf64_Xword r_offset; /* where to do it */ - Elf64_Xword r_info; /* index & type of relocation */ -} Elf64_Rel; - -typedef struct { - Elf64_Xword r_offset; /* where to do it */ - Elf64_Xword r_info; /* index & type of relocation */ - Elf64_Sxword r_addend; /* adjustment value */ -} Elf64_Rela; - -#define ELF64_R_SYM(info) ((info) >> 32) -#define ELF64_R_TYPE(info) ((info) & 0xFFFFFFFF) -#define ELF64_R_INFO(s,t) (((s) << 32) + (u_int32_t)(t)) - -/* Program Header */ -typedef struct { - Elf32_Word p_type; /* segment type */ - Elf32_Off p_offset; /* segment offset */ - Elf32_Addr p_vaddr; /* virtual address of segment */ - Elf32_Addr p_paddr; /* physical address - ignored? */ - Elf32_Word p_filesz; /* number of bytes in file for seg. */ - Elf32_Word p_memsz; /* number of bytes in mem. for seg. */ - Elf32_Word p_flags; /* flags */ - Elf32_Word p_align; /* memory alignment */ -} Elf32_Phdr; - -typedef struct { - Elf64_Half p_type; /* entry type */ - Elf64_Half p_flags; /* flags */ - Elf64_Off p_offset; /* offset */ - Elf64_Addr p_vaddr; /* virtual address */ - Elf64_Addr p_paddr; /* physical address */ - Elf64_Xword p_filesz; /* file size */ - Elf64_Xword p_memsz; /* memory size */ - Elf64_Xword p_align; /* memory & file alignment */ -} Elf64_Phdr; - -/* Segment types - p_type */ -#define PT_NULL 0 /* unused */ -#define PT_LOAD 1 /* loadable segment */ -#define PT_DYNAMIC 2 /* dynamic linking section */ -#define PT_INTERP 3 /* the RTLD */ -#define PT_NOTE 4 /* auxiliary information */ -#define PT_SHLIB 5 /* reserved - purpose undefined */ -#define PT_PHDR 6 /* program header */ -#define PT_NUM 7 /* Number of segment types */ -#define PT_LOPROC 0x70000000 /* reserved range for processor */ -#define PT_HIPROC 0x7fffffff /* specific segment types */ - -/* Segment flags - p_flags */ -#define PF_X 0x1 /* Executable */ -#define PF_W 0x2 /* Writable */ -#define PF_R 0x4 /* Readable */ -#define PF_MASKPROC 0xf0000000 /* reserved bits for processor */ - /* specific segment flags */ - -/* Dynamic structure */ -typedef struct { - Elf32_Sword d_tag; /* controls meaning of d_val */ - union { - Elf32_Word d_val; /* Multiple meanings - see d_tag */ - Elf32_Addr d_ptr; /* program virtual address */ - } d_un; -} Elf32_Dyn; - -typedef struct { - Elf64_Xword d_tag; /* controls meaning of d_val */ - union { - Elf64_Addr d_ptr; - Elf64_Xword d_val; - } d_un; -} Elf64_Dyn; - -/* Dynamic Array Tags - d_tag */ -#define DT_NULL 0 /* marks end of _DYNAMIC array */ -#define DT_NEEDED 1 /* string table offset of needed lib */ -#define DT_PLTRELSZ 2 /* size of relocation entries in PLT */ -#define DT_PLTGOT 3 /* address PLT/GOT */ -#define DT_HASH 4 /* address of symbol hash table */ -#define DT_STRTAB 5 /* address of string table */ -#define DT_SYMTAB 6 /* address of symbol table */ -#define DT_RELA 7 /* address of relocation table */ -#define DT_RELASZ 8 /* size of relocation table */ -#define DT_RELAENT 9 /* size of relocation entry */ -#define DT_STRSZ 10 /* size of string table */ -#define DT_SYMENT 11 /* size of symbol table entry */ -#define DT_INIT 12 /* address of initialization func. */ -#define DT_FINI 13 /* address of termination function */ -#define DT_SONAME 14 /* string table offset of shared obj */ -#define DT_RPATH 15 /* string table offset of library - search path */ -#define DT_SYMBOLIC 16 /* start sym search in shared obj. */ -#define DT_REL 17 /* address of rel. tbl. w addends */ -#define DT_RELSZ 18 /* size of DT_REL relocation table */ -#define DT_RELENT 19 /* size of DT_REL relocation entry */ -#define DT_PLTREL 20 /* PLT referenced relocation entry */ -#define DT_DEBUG 21 /* bugger */ -#define DT_TEXTREL 22 /* Allow rel. mod. to unwritable seg */ -#define DT_JMPREL 23 /* add. of PLT's relocation entries */ -#define DT_BIND_NOW 24 /* Bind now regardless of env setting */ -#define DT_NUM 25 /* Number used. */ -#define DT_LOPROC 0x70000000 /* reserved range for processor */ -#define DT_HIPROC 0x7fffffff /* specific dynamic array tags */ - -/* Standard ELF hashing function */ -unsigned int elf_hash(const unsigned char *name); - -/* - * Note Definitions - */ -typedef struct { - Elf32_Word namesz; - Elf32_Word descsz; - Elf32_Word type; -} Elf32_Note; - -typedef struct { - Elf64_Half namesz; - Elf64_Half descsz; - Elf64_Half type; -} Elf64_Note; - - -#if defined(ELFSIZE) -#define CONCAT(x,y) __CONCAT(x,y) -#define ELFNAME(x) CONCAT(elf,CONCAT(ELFSIZE,CONCAT(_,x))) -#define ELFNAME2(x,y) CONCAT(x,CONCAT(_elf,CONCAT(ELFSIZE,CONCAT(_,y)))) -#define ELFNAMEEND(x) CONCAT(x,CONCAT(_elf,ELFSIZE)) -#define ELFDEFNNAME(x) CONCAT(ELF,CONCAT(ELFSIZE,CONCAT(_,x))) -#endif - -#if defined(ELFSIZE) && (ELFSIZE == 32) -#define Elf_Ehdr Elf32_Ehdr -#define Elf_Phdr Elf32_Phdr -#define Elf_Shdr Elf32_Shdr -#define Elf_Sym Elf32_Sym -#define Elf_Rel Elf32_Rel -#define Elf_RelA Elf32_Rela -#define Elf_Dyn Elf32_Dyn -#define Elf_Word Elf32_Word -#define Elf_Sword Elf32_Sword -#define Elf_Addr Elf32_Addr -#define Elf_Off Elf32_Off -#define Elf_Nhdr Elf32_Nhdr -#define Elf_Note Elf32_Note - -#define ELF_R_SYM ELF32_R_SYM -#define ELF_R_TYPE ELF32_R_TYPE -#define ELF_R_INFO ELF32_R_INFO -#define ELFCLASS ELFCLASS32 - -#define ELF_ST_BIND ELF32_ST_BIND -#define ELF_ST_TYPE ELF32_ST_TYPE -#define ELF_ST_INFO ELF32_ST_INFO - -#define AuxInfo Aux32Info -#elif defined(ELFSIZE) && (ELFSIZE == 64) -#define Elf_Ehdr Elf64_Ehdr -#define Elf_Phdr Elf64_Phdr -#define Elf_Shdr Elf64_Shdr -#define Elf_Sym Elf64_Sym -#define Elf_Rel Elf64_Rel -#define Elf_RelA Elf64_Rela -#define Elf_Dyn Elf64_Dyn -#define Elf_Word Elf64_Word -#define Elf_Sword Elf64_Sword -#define Elf_Addr Elf64_Addr -#define Elf_Off Elf64_Off -#define Elf_Nhdr Elf64_Nhdr -#define Elf_Note Elf64_Note - -#define ELF_R_SYM ELF64_R_SYM -#define ELF_R_TYPE ELF64_R_TYPE -#define ELF_R_INFO ELF64_R_INFO -#define ELFCLASS ELFCLASS64 - -#define ELF_ST_BIND ELF64_ST_BIND -#define ELF_ST_TYPE ELF64_ST_TYPE -#define ELF_ST_INFO ELF64_ST_INFO - -#define AuxInfo Aux64Info -#endif - diff --git a/tools/xc/lib/xc_evtchn.c b/tools/xc/lib/xc_evtchn.c deleted file mode 100644 index 624f5b1c15..0000000000 --- a/tools/xc/lib/xc_evtchn.c +++ /dev/null @@ -1,131 +0,0 @@ -/****************************************************************************** - * xc_evtchn.c - * - * API for manipulating and accessing inter-domain event channels. - * - * Copyright (c) 2004, K A Fraser. - */ - -#include "xc_private.h" - - -static int do_evtchn_op(int xc_handle, evtchn_op_t *op) -{ - int ret = -1; - privcmd_hypercall_t hypercall; - - hypercall.op = __HYPERVISOR_event_channel_op; - hypercall.arg[0] = (unsigned long)op; - - if ( mlock(op, sizeof(*op)) != 0 ) - { - PERROR("Could not lock memory for Xen hypercall"); - goto out1; - } - - if ( (ret = do_xen_hypercall(xc_handle, &hypercall)) < 0 ) - goto out2; - - out2: (void)munlock(op, sizeof(*op)); - out1: return ret; -} - - -int xc_evtchn_bind_interdomain(int xc_handle, - u32 dom1, - u32 dom2, - int *port1, - int *port2) -{ - evtchn_op_t op; - int rc; - - op.cmd = EVTCHNOP_bind_interdomain; - op.u.bind_interdomain.dom1 = (domid_t)dom1; - op.u.bind_interdomain.dom2 = (domid_t)dom2; - - if ( (rc = do_evtchn_op(xc_handle, &op)) == 0 ) - { - if ( port1 != NULL ) - *port1 = op.u.bind_interdomain.port1; - if ( port2 != NULL ) - *port2 = op.u.bind_interdomain.port2; - } - - return rc; -} - - -int xc_evtchn_bind_virq(int xc_handle, - int virq, - int *port) -{ - evtchn_op_t op; - int rc; - - op.cmd = EVTCHNOP_bind_virq; - op.u.bind_virq.virq = (u32)virq; - - if ( (rc = do_evtchn_op(xc_handle, &op)) == 0 ) - { - if ( port != NULL ) - *port = op.u.bind_virq.port; - } - - return rc; -} - - -int xc_evtchn_close(int xc_handle, - u32 dom, - int port) -{ - evtchn_op_t op; - op.cmd = EVTCHNOP_close; - op.u.close.dom = (domid_t)dom; - op.u.close.port = port; - return do_evtchn_op(xc_handle, &op); -} - - -int xc_evtchn_send(int xc_handle, - int local_port) -{ - evtchn_op_t op; - op.cmd = EVTCHNOP_send; - op.u.send.local_port = local_port; - return do_evtchn_op(xc_handle, &op); -} - - -int xc_evtchn_status(int xc_handle, - u32 dom, - int port, - xc_evtchn_status_t *status) -{ - evtchn_op_t op; - int rc; - - op.cmd = EVTCHNOP_status; - op.u.status.dom = (domid_t)dom; - op.u.status.port = port; - - if ( (rc = do_evtchn_op(xc_handle, &op)) == 0 ) - { - switch ( status->status = op.u.status.status ) - { - case EVTCHNSTAT_interdomain: - status->u.interdomain.dom = (u32)op.u.status.u.interdomain.dom; - status->u.interdomain.port = op.u.status.u.interdomain.port; - break; - case EVTCHNSTAT_pirq: - status->u.pirq = op.u.status.u.pirq; - break; - case EVTCHNSTAT_virq: - status->u.virq = op.u.status.u.virq; - break; - } - } - - return rc; -} diff --git a/tools/xc/lib/xc_io.c b/tools/xc/lib/xc_io.c deleted file mode 100644 index 7d75ea245d..0000000000 --- a/tools/xc/lib/xc_io.c +++ /dev/null @@ -1,27 +0,0 @@ -#include "xc_io.h" - -void xcio_error(XcIOContext *ctxt, const char *msg, ...){ - va_list args; - - va_start(args, msg); - IOStream_vprint(ctxt->info, msg, args); - va_end(args); -} - -void xcio_info(XcIOContext *ctxt, const char *msg, ...){ - va_list args; - - if(!(ctxt->flags & XCFLAGS_VERBOSE)) return; - va_start(args, msg); - IOStream_vprint(ctxt->info, msg, args); - va_end(args); -} - -void xcio_debug(XcIOContext *ctxt, const char *msg, ...){ - va_list args; - - if(!(ctxt->flags & XCFLAGS_DEBUG)) return; - va_start(args, msg); - IOStream_vprint(ctxt->info, msg, args); - va_end(args); -} diff --git a/tools/xc/lib/xc_io.h b/tools/xc/lib/xc_io.h deleted file mode 100644 index 37febb52f1..0000000000 --- a/tools/xc/lib/xc_io.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef __XC_XC_IO_H__ -#define __XC_XC_IO_H__ - -#include "xc_private.h" -#include "iostream.h" - -typedef struct XcIOContext { - u32 domain; - unsigned flags; - IOStream *io; - IOStream *info; - IOStream *err; - char *vmconfig; - int vmconfig_n; -} XcIOContext; - -static inline int xcio_read(XcIOContext *ctxt, void *buf, int n){ - int rc; - - rc = IOStream_read(ctxt->io, buf, n); - return (rc == n ? 0 : rc); -} - -static inline int xcio_write(XcIOContext *ctxt, void *buf, int n){ - int rc; - - rc = IOStream_write(ctxt->io, buf, n); - return (rc == n ? 0 : rc); -} - -static inline int xcio_flush(XcIOContext *ctxt){ - return IOStream_flush(ctxt->io); -} - -extern void xcio_error(XcIOContext *ctxt, const char *msg, ...); -extern void xcio_info(XcIOContext *ctxt, const char *msg, ...); - -#define xcio_perror(_ctxt, _msg...) \ -xcio_error(_ctxt, "(errno %d %s)" _msg, errno, strerror(errno), ## _msg) - -#endif /* ! __XC_XC_IO_H__ */ - - - diff --git a/tools/xc/lib/xc_linux_build.c b/tools/xc/lib/xc_linux_build.c deleted file mode 100644 index ceace01b00..0000000000 --- a/tools/xc/lib/xc_linux_build.c +++ /dev/null @@ -1,675 +0,0 @@ -/****************************************************************************** - * xc_linux_build.c - */ - -#include "xc_private.h" -#define ELFSIZE 32 -#include "xc_elf.h" -#include - -#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED) -#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER) - -#define round_pgup(_p) (((_p)+(PAGE_SIZE-1))&PAGE_MASK) -#define round_pgdown(_p) ((_p)&PAGE_MASK) - -static int readelfimage_base_and_size(char *elfbase, - unsigned long elfsize, - unsigned long *pkernstart, - unsigned long *pkernend, - unsigned long *pkernentry); -static int loadelfimage(char *elfbase, int pmh, unsigned long *parray, - unsigned long vstart); - -static long get_tot_pages(int xc_handle, u32 domid) -{ - dom0_op_t op; - op.cmd = DOM0_GETDOMAININFO; - op.u.getdomaininfo.domain = (domid_t)domid; - op.u.getdomaininfo.ctxt = NULL; - return (do_dom0_op(xc_handle, &op) < 0) ? - -1 : op.u.getdomaininfo.tot_pages; -} - -static int get_pfn_list(int xc_handle, - u32 domid, - unsigned long *pfn_buf, - unsigned long max_pfns) -{ - dom0_op_t op; - int ret; - op.cmd = DOM0_GETMEMLIST; - op.u.getmemlist.domain = (domid_t)domid; - op.u.getmemlist.max_pfns = max_pfns; - op.u.getmemlist.buffer = pfn_buf; - - if ( mlock(pfn_buf, max_pfns * sizeof(unsigned long)) != 0 ) - return -1; - - ret = do_dom0_op(xc_handle, &op); - - (void)munlock(pfn_buf, max_pfns * sizeof(unsigned long)); - - return (ret < 0) ? -1 : op.u.getmemlist.num_pfns; -} - -static int copy_to_domain_page(int pm_handle, - unsigned long dst_pfn, - void *src_page) -{ - void *vaddr = map_pfn_writeable(pm_handle, dst_pfn); - if ( vaddr == NULL ) - return -1; - memcpy(vaddr, src_page, PAGE_SIZE); - unmap_pfn(pm_handle, vaddr); - return 0; -} - -static int setup_guestos(int xc_handle, - u32 dom, - char *image, unsigned long image_size, - gzFile initrd_gfd, unsigned long initrd_len, - unsigned long nr_pages, - unsigned long *pvsi, unsigned long *pvke, - full_execution_context_t *ctxt, - const char *cmdline, - unsigned long shared_info_frame, - unsigned int control_evtchn, - unsigned long flags) -{ - l1_pgentry_t *vl1tab=NULL, *vl1e=NULL; - l2_pgentry_t *vl2tab=NULL, *vl2e=NULL; - unsigned long *page_array = NULL; - unsigned long l2tab; - unsigned long l1tab; - unsigned long count, i; - extended_start_info_t *start_info; - shared_info_t *shared_info; - mmu_t *mmu = NULL; - int pm_handle=-1, rc; - - unsigned long nr_pt_pages; - unsigned long ppt_alloc; - unsigned long *physmap, *physmap_e, physmap_pfn; - - unsigned long v_start; - unsigned long vkern_start; - unsigned long vkern_entry; - unsigned long vkern_end; - unsigned long vinitrd_start; - unsigned long vinitrd_end; - unsigned long vphysmap_start; - unsigned long vphysmap_end; - unsigned long vstartinfo_start; - unsigned long vstartinfo_end; - unsigned long vstack_start; - unsigned long vstack_end; - unsigned long vpt_start; - unsigned long vpt_end; - unsigned long v_end; - - rc = readelfimage_base_and_size(image, image_size, - &vkern_start, &vkern_end, &vkern_entry); - if ( rc != 0 ) - goto error_out; - - /* - * Why do we need this? The number of page-table frames depends on the - * size of the bootstrap address space. But the size of the address space - * depends on the number of page-table frames (since each one is mapped - * read-only). We have a pair of simultaneous equations in two unknowns, - * which we solve by exhaustive search. - */ - for ( nr_pt_pages = 2; ; nr_pt_pages++ ) - { - v_start = vkern_start & ~((1<<22)-1); - vinitrd_start = round_pgup(vkern_end); - vinitrd_end = vinitrd_start + initrd_len; - vphysmap_start = round_pgup(vinitrd_end); - vphysmap_end = vphysmap_start + (nr_pages * sizeof(unsigned long)); - vpt_start = round_pgup(vphysmap_end); - vpt_end = vpt_start + (nr_pt_pages * PAGE_SIZE); - vstartinfo_start = vpt_end; - vstartinfo_end = vstartinfo_start + PAGE_SIZE; - vstack_start = vstartinfo_end; - vstack_end = vstack_start + PAGE_SIZE; - v_end = (vstack_end + (1<<22)-1) & ~((1<<22)-1); - if ( (v_end - vstack_end) < (512 << 10) ) - v_end += 1 << 22; /* Add extra 4MB to get >= 512kB padding. */ - if ( (((v_end - v_start) >> L2_PAGETABLE_SHIFT) + 1) <= nr_pt_pages ) - break; - } - - if ( (v_end - v_start) > (nr_pages * PAGE_SIZE) ) - { - printf("Initial guest OS requires too much space\n" - "(%luMB is greater than %luMB limit)\n", - (v_end-v_start)>>20, (nr_pages<>20); - goto error_out; - } - - printf("VIRTUAL MEMORY ARRANGEMENT:\n" - " Loaded kernel: %08lx->%08lx\n" - " Init. ramdisk: %08lx->%08lx\n" - " Phys-Mach map: %08lx->%08lx\n" - " Page tables: %08lx->%08lx\n" - " Start info: %08lx->%08lx\n" - " Boot stack: %08lx->%08lx\n" - " TOTAL: %08lx->%08lx\n", - vkern_start, vkern_end, - vinitrd_start, vinitrd_end, - vphysmap_start, vphysmap_end, - vpt_start, vpt_end, - vstartinfo_start, vstartinfo_end, - vstack_start, vstack_end, - v_start, v_end); - printf(" ENTRY ADDRESS: %08lx\n", vkern_entry); - - if ( (pm_handle = init_pfn_mapper((domid_t)dom)) < 0 ) - goto error_out; - - if ( (page_array = malloc(nr_pages * sizeof(unsigned long))) == NULL ) - { - PERROR("Could not allocate memory"); - goto error_out; - } - - if ( get_pfn_list(xc_handle, dom, page_array, nr_pages) != nr_pages ) - { - PERROR("Could not get the page frame list"); - goto error_out; - } - - loadelfimage(image, pm_handle, page_array, v_start); - - /* Load the initial ramdisk image. */ - if ( initrd_len != 0 ) - { - for ( i = (vinitrd_start - v_start); - i < (vinitrd_end - v_start); i += PAGE_SIZE ) - { - char page[PAGE_SIZE]; - if ( gzread(initrd_gfd, page, PAGE_SIZE) == -1 ) - { - PERROR("Error reading initrd image, could not"); - goto error_out; - } - copy_to_domain_page(pm_handle, - page_array[i>>PAGE_SHIFT], page); - } - } - - if ( (mmu = init_mmu_updates(xc_handle, dom)) == NULL ) - goto error_out; - - /* First allocate page for page dir. */ - ppt_alloc = (vpt_start - v_start) >> PAGE_SHIFT; - l2tab = page_array[ppt_alloc++] << PAGE_SHIFT; - ctxt->pt_base = l2tab; - - /* Initialise the page tables. */ - if ( (vl2tab = map_pfn_writeable(pm_handle, l2tab >> PAGE_SHIFT)) == NULL ) - goto error_out; - memset(vl2tab, 0, PAGE_SIZE); - vl2e = &vl2tab[l2_table_offset(v_start)]; - for ( count = 0; count < ((v_end-v_start)>>PAGE_SHIFT); count++ ) - { - if ( ((unsigned long)vl1e & (PAGE_SIZE-1)) == 0 ) - { - l1tab = page_array[ppt_alloc++] << PAGE_SHIFT; - if ( vl1tab != NULL ) - unmap_pfn(pm_handle, vl1tab); - if ( (vl1tab = map_pfn_writeable(pm_handle, - l1tab >> PAGE_SHIFT)) == NULL ) - goto error_out; - memset(vl1tab, 0, PAGE_SIZE); - vl1e = &vl1tab[l1_table_offset(v_start + (count<= ((vpt_start-v_start)>>PAGE_SHIFT)) && - (count < ((vpt_end -v_start)>>PAGE_SHIFT)) ) - *vl1e &= ~_PAGE_RW; - vl1e++; - } - unmap_pfn(pm_handle, vl1tab); - unmap_pfn(pm_handle, vl2tab); - - /* Write the phys->machine and machine->phys table entries. */ - physmap_pfn = (vphysmap_start - v_start) >> PAGE_SHIFT; - physmap = physmap_e = - map_pfn_writeable(pm_handle, page_array[physmap_pfn++]); - for ( count = 0; count < nr_pages; count++ ) - { - if ( add_mmu_update(xc_handle, mmu, - (page_array[count] << PAGE_SHIFT) | - MMU_MACHPHYS_UPDATE, count) ) - goto error_out; - *physmap_e++ = page_array[count]; - if ( ((unsigned long)physmap_e & (PAGE_SIZE-1)) == 0 ) - { - unmap_pfn(pm_handle, physmap); - physmap = physmap_e = - map_pfn_writeable(pm_handle, page_array[physmap_pfn++]); - } - } - unmap_pfn(pm_handle, physmap); - - /* - * Pin down l2tab addr as page dir page - causes hypervisor to provide - * correct protection for the page - */ - if ( add_mmu_update(xc_handle, mmu, - l2tab | MMU_EXTENDED_COMMAND, MMUEXT_PIN_L2_TABLE) ) - goto error_out; - - start_info = map_pfn_writeable( - pm_handle, page_array[(vstartinfo_start-v_start)>>PAGE_SHIFT]); - memset(start_info, 0, sizeof(*start_info)); - start_info->nr_pages = nr_pages; - start_info->shared_info = shared_info_frame << PAGE_SHIFT; - start_info->flags = flags; - start_info->pt_base = vpt_start; - start_info->nr_pt_frames = nr_pt_pages; - start_info->mfn_list = vphysmap_start; - start_info->domain_controller_evtchn = control_evtchn; - if ( initrd_len != 0 ) - { - start_info->mod_start = vinitrd_start; - start_info->mod_len = initrd_len; - } - strncpy(start_info->cmd_line, cmdline, MAX_CMDLINE); - start_info->cmd_line[MAX_CMDLINE-1] = '\0'; - unmap_pfn(pm_handle, start_info); - - /* shared_info page starts its life empty. */ - shared_info = map_pfn_writeable(pm_handle, shared_info_frame); - memset(shared_info, 0, sizeof(shared_info_t)); - /* Mask all upcalls... */ - for ( i = 0; i < MAX_VIRT_CPUS; i++ ) - shared_info->vcpu_data[i].evtchn_upcall_mask = 1; - unmap_pfn(pm_handle, shared_info); - - /* Send the page update requests down to the hypervisor. */ - if ( finish_mmu_updates(xc_handle, mmu) ) - goto error_out; - - free(mmu); - (void)close_pfn_mapper(pm_handle); - free(page_array); - - *pvsi = vstartinfo_start; - *pvke = vkern_entry; - - return 0; - - error_out: - if ( mmu != NULL ) - free(mmu); - if ( pm_handle >= 0 ) - (void)close_pfn_mapper(pm_handle); - if ( page_array != NULL ) - free(page_array); - return -1; -} - -static unsigned long get_filesz(int fd) -{ - u16 sig; - u32 _sz = 0; - unsigned long sz; - - lseek(fd, 0, SEEK_SET); - read(fd, &sig, sizeof(sig)); - sz = lseek(fd, 0, SEEK_END); - if ( sig == 0x8b1f ) /* GZIP signature? */ - { - lseek(fd, -4, SEEK_END); - read(fd, &_sz, 4); - sz = _sz; - } - lseek(fd, 0, SEEK_SET); - - return sz; -} - -static char *read_kernel_image(const char *filename, unsigned long *size) -{ - int kernel_fd = -1; - gzFile kernel_gfd = NULL; - char *image = NULL; - unsigned int bytes; - - if ( (kernel_fd = open(filename, O_RDONLY)) < 0 ) - { - PERROR("Could not open kernel image"); - goto out; - } - - *size = get_filesz(kernel_fd); - - if ( (kernel_gfd = gzdopen(kernel_fd, "rb")) == NULL ) - { - PERROR("Could not allocate decompression state for state file"); - goto out; - } - - if ( (image = malloc(*size)) == NULL ) - { - PERROR("Could not allocate memory for kernel image"); - goto out; - } - - if ( (bytes = gzread(kernel_gfd, image, *size)) != *size ) - { - PERROR("Error reading kernel image, could not" - " read the whole image (%d != %ld).", bytes, *size); - free(image); - image = NULL; - } - - out: - if ( kernel_gfd != NULL ) - gzclose(kernel_gfd); - else if ( kernel_fd >= 0 ) - close(kernel_fd); - return image; -} - -int xc_linux_build(int xc_handle, - u32 domid, - const char *image_name, - const char *ramdisk_name, - const char *cmdline, - unsigned int control_evtchn, - unsigned long flags) -{ - dom0_op_t launch_op, op; - int initrd_fd = -1; - gzFile initrd_gfd = NULL; - int rc, i; - full_execution_context_t st_ctxt, *ctxt = &st_ctxt; - unsigned long nr_pages; - char *image = NULL; - unsigned long image_size, initrd_size=0; - unsigned long vstartinfo_start, vkern_entry; - - if ( (nr_pages = get_tot_pages(xc_handle, domid)) < 0 ) - { - PERROR("Could not find total pages for domain"); - goto error_out; - } - - if ( (image = read_kernel_image(image_name, &image_size)) == NULL ) - goto error_out; - - if ( (ramdisk_name != NULL) && (strlen(ramdisk_name) != 0) ) - { - if ( (initrd_fd = open(ramdisk_name, O_RDONLY)) < 0 ) - { - PERROR("Could not open the initial ramdisk image"); - goto error_out; - } - - initrd_size = get_filesz(initrd_fd); - - if ( (initrd_gfd = gzdopen(initrd_fd, "rb")) == NULL ) - { - PERROR("Could not allocate decompression state for initrd"); - goto error_out; - } - } - - if ( mlock(&st_ctxt, sizeof(st_ctxt) ) ) - { - PERROR("Unable to mlock ctxt"); - return 1; - } - - op.cmd = DOM0_GETDOMAININFO; - op.u.getdomaininfo.domain = (domid_t)domid; - op.u.getdomaininfo.ctxt = ctxt; - if ( (do_dom0_op(xc_handle, &op) < 0) || - ((u32)op.u.getdomaininfo.domain != domid) ) - { - PERROR("Could not get info on domain"); - goto error_out; - } - if ( !(op.u.getdomaininfo.flags & DOMFLAGS_PAUSED) || - (ctxt->pt_base != 0) ) - { - ERROR("Domain is already constructed"); - goto error_out; - } - - if ( setup_guestos(xc_handle, domid, image, image_size, - initrd_gfd, initrd_size, nr_pages, - &vstartinfo_start, &vkern_entry, - ctxt, cmdline, - op.u.getdomaininfo.shared_info_frame, - control_evtchn, flags) < 0 ) - { - ERROR("Error constructing guest OS"); - goto error_out; - } - - if ( initrd_fd >= 0 ) - close(initrd_fd); - if ( initrd_gfd ) - gzclose(initrd_gfd); - if ( image != NULL ) - free(image); - - ctxt->flags = 0; - - /* - * Initial register values: - * DS,ES,FS,GS = FLAT_GUESTOS_DS - * CS:EIP = FLAT_GUESTOS_CS:start_pc - * SS:ESP = FLAT_GUESTOS_DS:start_stack - * ESI = start_info - * [EAX,EBX,ECX,EDX,EDI,EBP are zero] - * EFLAGS = IF | 2 (bit 1 is reserved and should always be 1) - */ - ctxt->cpu_ctxt.ds = FLAT_GUESTOS_DS; - ctxt->cpu_ctxt.es = FLAT_GUESTOS_DS; - ctxt->cpu_ctxt.fs = FLAT_GUESTOS_DS; - ctxt->cpu_ctxt.gs = FLAT_GUESTOS_DS; - ctxt->cpu_ctxt.ss = FLAT_GUESTOS_DS; - ctxt->cpu_ctxt.cs = FLAT_GUESTOS_CS; - ctxt->cpu_ctxt.eip = vkern_entry; - ctxt->cpu_ctxt.esp = vstartinfo_start; - ctxt->cpu_ctxt.esi = vstartinfo_start; - ctxt->cpu_ctxt.eflags = (1<<9) | (1<<2); - - /* FPU is set up to default initial state. */ - memset(ctxt->fpu_ctxt, 0, sizeof(ctxt->fpu_ctxt)); - - /* Virtual IDT is empty at start-of-day. */ - for ( i = 0; i < 256; i++ ) - { - ctxt->trap_ctxt[i].vector = i; - ctxt->trap_ctxt[i].cs = FLAT_GUESTOS_CS; - } - ctxt->fast_trap_idx = 0; - - /* No LDT. */ - ctxt->ldt_ents = 0; - - /* Use the default Xen-provided GDT. */ - ctxt->gdt_ents = 0; - - /* Ring 1 stack is the initial stack. */ - ctxt->guestos_ss = FLAT_GUESTOS_DS; - ctxt->guestos_esp = vstartinfo_start; - - /* No debugging. */ - memset(ctxt->debugreg, 0, sizeof(ctxt->debugreg)); - - /* No callback handlers. */ - ctxt->event_callback_cs = FLAT_GUESTOS_CS; - ctxt->event_callback_eip = 0; - ctxt->failsafe_callback_cs = FLAT_GUESTOS_CS; - ctxt->failsafe_callback_eip = 0; - - memset( &launch_op, 0, sizeof(launch_op) ); - - launch_op.u.builddomain.domain = (domid_t)domid; - launch_op.u.builddomain.ctxt = ctxt; - - launch_op.cmd = DOM0_BUILDDOMAIN; - rc = do_dom0_op(xc_handle, &launch_op); - - return rc; - - error_out: - if ( initrd_gfd != NULL ) - gzclose(initrd_gfd); - else if ( initrd_fd >= 0 ) - close(initrd_fd); - if ( image != NULL ) - free(image); - - return -1; -} - -static inline int is_loadable_phdr(Elf_Phdr *phdr) -{ - return ((phdr->p_type == PT_LOAD) && - ((phdr->p_flags & (PF_W|PF_X)) != 0)); -} - -static int readelfimage_base_and_size(char *elfbase, - unsigned long elfsize, - unsigned long *pkernstart, - unsigned long *pkernend, - unsigned long *pkernentry) -{ - Elf_Ehdr *ehdr = (Elf_Ehdr *)elfbase; - Elf_Phdr *phdr; - Elf_Shdr *shdr; - unsigned long kernstart = ~0UL, kernend=0UL; - char *shstrtab, *guestinfo; - int h; - - if ( !IS_ELF(*ehdr) ) - { - ERROR("Kernel image does not have an ELF header."); - return -EINVAL; - } - - if ( (ehdr->e_phoff + (ehdr->e_phnum * ehdr->e_phentsize)) > elfsize ) - { - ERROR("ELF program headers extend beyond end of image."); - return -EINVAL; - } - - if ( (ehdr->e_shoff + (ehdr->e_shnum * ehdr->e_shentsize)) > elfsize ) - { - ERROR("ELF section headers extend beyond end of image."); - return -EINVAL; - } - - /* Find the section-header strings table. */ - if ( ehdr->e_shstrndx == SHN_UNDEF ) - { - ERROR("ELF image has no section-header strings table (shstrtab)."); - return -EINVAL; - } - shdr = (Elf_Shdr *)(elfbase + ehdr->e_shoff + - (ehdr->e_shstrndx*ehdr->e_shentsize)); - shstrtab = elfbase + shdr->sh_offset; - - /* Find the special '__xen_guest' section and check its contents. */ - for ( h = 0; h < ehdr->e_shnum; h++ ) - { - shdr = (Elf_Shdr *)(elfbase + ehdr->e_shoff + (h*ehdr->e_shentsize)); - if ( strcmp(&shstrtab[shdr->sh_name], "__xen_guest") != 0 ) - continue; - guestinfo = elfbase + shdr->sh_offset; - if ( (strstr(guestinfo, "GUEST_OS=linux") == NULL) || - (strstr(guestinfo, "XEN_VER=1.3") == NULL) ) - { - ERROR("Will only load Linux images built for Xen v1.3"); - ERROR("Actually saw: '%s'", guestinfo); - return -EINVAL; - } - break; - } - if ( h == ehdr->e_shnum ) - { - ERROR("Not a Xen-ELF image: '__xen_guest' section not found."); - return -EINVAL; - } - - for ( h = 0; h < ehdr->e_phnum; h++ ) - { - phdr = (Elf_Phdr *)(elfbase + ehdr->e_phoff + (h*ehdr->e_phentsize)); - if ( !is_loadable_phdr(phdr) ) - continue; - if ( phdr->p_vaddr < kernstart ) - kernstart = phdr->p_vaddr; - if ( (phdr->p_vaddr + phdr->p_memsz) > kernend ) - kernend = phdr->p_vaddr + phdr->p_memsz; - } - - if ( (kernstart > kernend) || - (ehdr->e_entry < kernstart) || - (ehdr->e_entry > kernend) ) - { - ERROR("Malformed ELF image."); - return -EINVAL; - } - - *pkernstart = kernstart; - *pkernend = kernend; - *pkernentry = ehdr->e_entry; - - return 0; -} - -static int loadelfimage(char *elfbase, int pmh, unsigned long *parray, - unsigned long vstart) -{ - Elf_Ehdr *ehdr = (Elf_Ehdr *)elfbase; - Elf_Phdr *phdr; - int h; - - char *va; - unsigned long pa, done, chunksz; - - for ( h = 0; h < ehdr->e_phnum; h++ ) - { - phdr = (Elf_Phdr *)(elfbase + ehdr->e_phoff + (h*ehdr->e_phentsize)); - if ( !is_loadable_phdr(phdr) ) - continue; - - for ( done = 0; done < phdr->p_filesz; done += chunksz ) - { - pa = (phdr->p_vaddr + done) - vstart; - va = map_pfn_writeable(pmh, parray[pa>>PAGE_SHIFT]); - va += pa & (PAGE_SIZE-1); - chunksz = phdr->p_filesz - done; - if ( chunksz > (PAGE_SIZE - (pa & (PAGE_SIZE-1))) ) - chunksz = PAGE_SIZE - (pa & (PAGE_SIZE-1)); - memcpy(va, elfbase + phdr->p_offset + done, chunksz); - unmap_pfn(pmh, va); - } - - for ( ; done < phdr->p_memsz; done += chunksz ) - { - pa = (phdr->p_vaddr + done) - vstart; - va = map_pfn_writeable(pmh, parray[pa>>PAGE_SHIFT]); - va += pa & (PAGE_SIZE-1); - chunksz = phdr->p_memsz - done; - if ( chunksz > (PAGE_SIZE - (pa & (PAGE_SIZE-1))) ) - chunksz = PAGE_SIZE - (pa & (PAGE_SIZE-1)); - memset(va, 0, chunksz); - unmap_pfn(pmh, va); - } - } - - return 0; -} - diff --git a/tools/xc/lib/xc_linux_restore.c b/tools/xc/lib/xc_linux_restore.c deleted file mode 100644 index badba75162..0000000000 --- a/tools/xc/lib/xc_linux_restore.c +++ /dev/null @@ -1,600 +0,0 @@ -/****************************************************************************** - * xc_linux_restore.c - * - * Restore the state of a Linux session. - * - * Copyright (c) 2003, K A Fraser. - */ - -#include "xc_private.h" -#include - -#define MAX_BATCH_SIZE 1024 - -#define DEBUG 0 - -#if DEBUG -#define DPRINTF(_f, _a...) printf ( _f , ## _a ) -#else -#define DPRINTF(_f, _a...) ((void)0) -#endif - - -static int get_pfn_list(int xc_handle, - u32 domain_id, - unsigned long *pfn_buf, - unsigned long max_pfns) -{ - dom0_op_t op; - int ret; - op.cmd = DOM0_GETMEMLIST; - op.u.getmemlist.domain = (domid_t)domain_id; - op.u.getmemlist.max_pfns = max_pfns; - op.u.getmemlist.buffer = pfn_buf; - - if ( mlock(pfn_buf, max_pfns * sizeof(unsigned long)) != 0 ) - { - PERROR("Could not lock pfn list buffer"); - return -1; - } - - ret = do_dom0_op(xc_handle, &op); - - (void)munlock(pfn_buf, max_pfns * sizeof(unsigned long)); - - return (ret < 0) ? -1 : op.u.getmemlist.num_pfns; -} - -/** Read the vmconfig string from the state input. - * It is stored as a 4-byte count 'n' followed by n bytes. - * The config data is stored in a new string in 'ioctxt->vmconfig', - * and is null-terminated. The count is stored in 'ioctxt->vmconfig_n'. - * - * @param ioctxt i/o context - * @return 0 on success, non-zero on error. - */ -static int read_vmconfig(XcIOContext *ioctxt){ - int err = -1; - if(xcio_read(ioctxt, &ioctxt->vmconfig_n, sizeof(ioctxt->vmconfig_n))){ - goto exit; - } - ioctxt->vmconfig = malloc(ioctxt->vmconfig_n + 1); - if(!ioctxt->vmconfig) goto exit; - if(xcio_read(ioctxt, ioctxt->vmconfig, ioctxt->vmconfig_n)){ - goto exit; - } - ioctxt->vmconfig[ioctxt->vmconfig_n] = '\0'; - err = 0; - exit: - if(err){ - if(ioctxt->vmconfig){ - free(ioctxt->vmconfig); - } - ioctxt->vmconfig = NULL; - ioctxt->vmconfig_n = 0; - } - return err; -} - -int xc_linux_restore(int xc_handle, XcIOContext *ioctxt) -{ - dom0_op_t op; - int rc = 1, i, n, k; - unsigned long mfn, pfn, xpfn; - unsigned int prev_pc, this_pc; - u32 dom = ioctxt->domain; - int verify = 0; - - /* Number of page frames in use by this Linux session. */ - unsigned long nr_pfns; - - /* The new domain's shared-info frame number. */ - unsigned long shared_info_frame; - unsigned char shared_info[PAGE_SIZE]; /* saved contents from file */ - - /* A copy of the CPU context of the guest. */ - full_execution_context_t ctxt; - - /* First 16 bytes of the state file must contain 'LinuxGuestRecord'. */ - char signature[16]; - - /* A copy of the domain's name. */ - char name[MAX_DOMAIN_NAME]; - - /* A table containg the type of each PFN (/not/ MFN!). */ - unsigned long *pfn_type = NULL; - - /* A table of MFNs to map in the current region */ - unsigned long *region_mfn = NULL; - - /* A temporary mapping, and a copy, of one frame of guest memory. */ - unsigned long *ppage; - - /* A copy of the pfn-to-mfn table frame list. */ - unsigned long pfn_to_mfn_frame_list[1024]; - - /* A table mapping each PFN to its new MFN. */ - unsigned long *pfn_to_mfn_table = NULL; - - /* used by mapper for updating the domain's copy of the table */ - unsigned long *live_pfn_to_mfn_table = NULL; - - /* A temporary mapping of the guest's suspend record. */ - suspend_record_t *p_srec; - - char *region_base; - - mmu_t *mmu = NULL; - - int pm_handle = -1; - - /* used by debug verify code */ - unsigned long buf[PAGE_SIZE/sizeof(unsigned long)]; - - if ( mlock(&ctxt, sizeof(ctxt) ) ) { - /* needed for when we do the build dom0 op, - but might as well do early */ - PERROR("Unable to mlock ctxt"); - return 1; - } - - /* Start writing out the saved-domain record. */ - if ( xcio_read(ioctxt, signature, 16) || - (memcmp(signature, "LinuxGuestRecord", 16) != 0) ) { - xcio_error(ioctxt, "Unrecognised state format -- no signature found"); - goto out; - } - - if ( xcio_read(ioctxt, name, sizeof(name)) || - xcio_read(ioctxt, &nr_pfns, sizeof(unsigned long)) || - xcio_read(ioctxt, pfn_to_mfn_frame_list, PAGE_SIZE) ) { - xcio_error(ioctxt, "Error reading header"); - goto out; - } - - if(read_vmconfig(ioctxt)){ - xcio_error(ioctxt, "Error writing vmconfig"); - goto out; - } - - for ( i = 0; i < MAX_DOMAIN_NAME; i++ ) { - if ( name[i] == '\0' ) break; - if ( name[i] & 0x80 ) - { - xcio_error(ioctxt, "Random characters in domain name"); - goto out; - } - } - name[MAX_DOMAIN_NAME-1] = '\0'; - - if ( nr_pfns > 1024*1024 ) { - xcio_error(ioctxt, "Invalid state file -- pfn count out of range"); - goto out; - } - - /* We want zeroed memory so use calloc rather than malloc. */ - pfn_to_mfn_table = calloc(1, 4 * nr_pfns); - pfn_type = calloc(1, 4 * nr_pfns); - region_mfn = calloc(1, 4 * MAX_BATCH_SIZE); - - if ( (pfn_to_mfn_table == NULL) || (pfn_type == NULL) || - (region_mfn == NULL) ) { - errno = ENOMEM; - goto out; - } - - if ( mlock(region_mfn, 4 * MAX_BATCH_SIZE ) ) { - xcio_error(ioctxt, "Could not mlock region_mfn"); - goto out; - } - - /* Set the domain's name to that from the restore file */ - if ( xc_domain_setname( xc_handle, dom, name ) ) { - xcio_error(ioctxt, "Could not set domain name"); - goto out; - } - - /* Set the domain's initial memory allocation - to that from the restore file */ - - if ( xc_domain_setinitialmem(xc_handle, dom, - nr_pfns * (PAGE_SIZE / 1024)) ) - { - xcio_error(ioctxt, "Could not set domain initial memory"); - goto out; - } - - /* Get the domain's shared-info frame. */ - op.cmd = DOM0_GETDOMAININFO; - op.u.getdomaininfo.domain = (domid_t)dom; - op.u.getdomaininfo.ctxt = NULL; - if ( do_dom0_op(xc_handle, &op) < 0 ) { - xcio_error(ioctxt, "Could not get information on new domain"); - goto out; - } - shared_info_frame = op.u.getdomaininfo.shared_info_frame; - - if ( (pm_handle = init_pfn_mapper((domid_t)dom)) < 0 ) - goto out; - - - - /* Build the pfn-to-mfn table. We choose MFN ordering returned by Xen. */ - if ( get_pfn_list(xc_handle, dom, pfn_to_mfn_table, nr_pfns) != nr_pfns ) { - xcio_error(ioctxt, "Did not read correct number of frame numbers for new dom"); - goto out; - } - - if ( (mmu = init_mmu_updates(xc_handle, dom)) == NULL ) { - xcio_error(ioctxt, "Could not initialise for MMU updates"); - goto out; - } - - xcio_info(ioctxt, "Reloading memory pages: 0%%"); - - /* - * Now simply read each saved frame into its new machine frame. - * We uncanonicalise page tables as we go. - */ - prev_pc = 0; - - n=0; - while(1) { - int j; - unsigned long region_pfn_type[MAX_BATCH_SIZE]; - - this_pc = (n * 100) / nr_pfns; - if ( (this_pc - prev_pc) >= 5 ) { - xcio_info(ioctxt, "\b\b\b\b%3d%%", this_pc); - prev_pc = this_pc; - } - - if ( xcio_read(ioctxt, &j, sizeof(int)) ) { - xcio_error(ioctxt, "Error when reading from state file"); - goto out; - } - - DPRINTF("batch %d\n",j); - - if ( j == -1 ) { - verify = 1; - printf("Entering page verify mode\n"); - continue; - } - - if ( j == 0 ) break; /* our work here is done */ - - if( j > MAX_BATCH_SIZE ) { - xcio_error(ioctxt, "Max batch size exceeded. Giving up."); - goto out; - } - - if ( xcio_read(ioctxt, region_pfn_type, j*sizeof(unsigned long)) ) { - xcio_error(ioctxt, "Error when reading from state file"); - goto out; - } - - for(i=0; inr_pfns) { - xcio_error(ioctxt, "pfn out of range"); - goto out; - } - - region_pfn_type[i] &= LTAB_MASK; - - pfn_type[pfn] = region_pfn_type[i]; - - mfn = pfn_to_mfn_table[pfn]; - - if ( verify ) { - ppage = (unsigned long*) buf; /* debug case */ - } else { - ppage = (unsigned long*) (region_base + i*PAGE_SIZE); - } - - if ( xcio_read(ioctxt, ppage, PAGE_SIZE) ) { - xcio_error(ioctxt, "Error when reading from state file"); - goto out; - } - - switch( region_pfn_type[i] ) { - case 0: - break; - - case L1TAB: - { - for ( k = 0; k < 1024; k++ ) { - if ( ppage[k] & _PAGE_PRESENT ) { - xpfn = ppage[k] >> PAGE_SHIFT; - - if ( xpfn >= nr_pfns ) { - xcio_error(ioctxt, "Frame number in type %lu page table is " - "out of range. i=%d k=%d pfn=0x%lx " - "nr_pfns=%lu", region_pfn_type[i]>>28, i, - k, xpfn, nr_pfns); - goto out; - } - - ppage[k] &= (PAGE_SIZE - 1) & - ~(_PAGE_GLOBAL | _PAGE_PAT); - ppage[k] |= pfn_to_mfn_table[xpfn] << PAGE_SHIFT; - } - } - } - break; - - case L2TAB: - { - for ( k = 0; - k < (HYPERVISOR_VIRT_START>>L2_PAGETABLE_SHIFT); - k++ ) { - if ( ppage[k] & _PAGE_PRESENT ) { - xpfn = ppage[k] >> PAGE_SHIFT; - - if ( xpfn >= nr_pfns ) { - xcio_error(ioctxt, "Frame number in type %lu page table is " - "out of range. i=%d k=%d pfn=%lu nr_pfns=%lu", - region_pfn_type[i]>>28, i, k, xpfn, nr_pfns); - - goto out; - } - - ppage[k] &= (PAGE_SIZE - 1) & - ~(_PAGE_GLOBAL | _PAGE_PSE); - ppage[k] |= pfn_to_mfn_table[xpfn] << PAGE_SHIFT; - } - } - } - break; - - default: - xcio_error(ioctxt, "Bogus page type %lx page table is out of range." - " i=%d nr_pfns=%lu", region_pfn_type[i], i, nr_pfns); - goto out; - - } /* end of page type switch statement */ - - if ( verify ) { - int res = memcmp(buf, (region_base + i*PAGE_SIZE), PAGE_SIZE ); - if (res) { - int v; - printf("************** pfn=%lx type=%lx gotcs=%08lx " - "actualcs=%08lx\n", pfn, pfn_type[pfn], - csum_page(region_base + i*PAGE_SIZE), - csum_page(buf)); - for ( v = 0; v < 4; v++ ) { - unsigned long *p = (unsigned long *) - (region_base + i*PAGE_SIZE); - if ( buf[v] != p[v] ) - printf(" %d: %08lx %08lx\n", - v, buf[v], p[v] ); - } - } - } - - if ( add_mmu_update(xc_handle, mmu, - (mfn<= nr_pfns) || (pfn_type[pfn] != NOTAB) ) - { - xcio_error(ioctxt, "Suspend record frame number is bad"); - goto out; - } - ctxt.cpu_ctxt.esi = mfn = pfn_to_mfn_table[pfn]; - p_srec = map_pfn_writeable(pm_handle, mfn); - p_srec->resume_info.nr_pages = nr_pfns; - p_srec->resume_info.shared_info = shared_info_frame << PAGE_SHIFT; - p_srec->resume_info.flags = 0; - unmap_pfn(pm_handle, p_srec); - - /* Uncanonicalise each GDT frame number. */ - if ( ctxt.gdt_ents > 8192 ) { - xcio_error(ioctxt, "GDT entry count out of range"); - goto out; - } - for ( i = 0; i < ctxt.gdt_ents; i += 512 ) { - pfn = ctxt.gdt_frames[i]; - if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NOTAB) ) { - xcio_error(ioctxt, "GDT frame number is bad"); - goto out; - } - ctxt.gdt_frames[i] = pfn_to_mfn_table[pfn]; - } - - /* Uncanonicalise the page table base pointer. */ - pfn = ctxt.pt_base >> PAGE_SHIFT; - if ( (pfn >= nr_pfns) || (pfn_type[pfn] != L2TAB) ) { - printf("PT base is bad. pfn=%lu nr=%lu type=%08lx %08lx\n", - pfn, nr_pfns, pfn_type[pfn], (unsigned long)L2TAB); - xcio_error(ioctxt, "PT base is bad."); - goto out; - } - ctxt.pt_base = pfn_to_mfn_table[pfn] << PAGE_SHIFT; - - - /* clear any pending events and the selector */ - memset( &(((shared_info_t *)shared_info)->evtchn_pending[0]), - 0, sizeof (((shared_info_t *)shared_info)->evtchn_pending)+ - sizeof(((shared_info_t *)shared_info)->evtchn_pending_sel) ); - - /* Copy saved contents of shared-info page. No checking needed. */ - ppage = map_pfn_writeable(pm_handle, shared_info_frame); - memcpy(ppage, shared_info, sizeof(shared_info_t)); - unmap_pfn(pm_handle, ppage); - - - /* Uncanonicalise the pfn-to-mfn table frame-number list. */ - for ( i = 0; i < (nr_pfns+1023)/1024; i++ ) { - unsigned long pfn, mfn; - - pfn = pfn_to_mfn_frame_list[i]; - if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NOTAB) ) { - xcio_error(ioctxt, "PFN-to-MFN frame number is bad"); - goto out; - } - mfn = pfn_to_mfn_table[pfn]; - pfn_to_mfn_frame_list[i] = mfn; - } - - if ( (live_pfn_to_mfn_table = - mfn_mapper_map_batch(xc_handle, dom, - PROT_WRITE, - pfn_to_mfn_frame_list, - (nr_pfns+1023)/1024 )) == 0 ) { - xcio_error(ioctxt, "Couldn't map pfn_to_mfn table"); - goto out; - } - - memcpy( live_pfn_to_mfn_table, pfn_to_mfn_table, - nr_pfns*sizeof(unsigned long) ); - - munmap( live_pfn_to_mfn_table, ((nr_pfns+1023)/1024)*PAGE_SIZE ); - - /* - * Safety checking of saved context: - * 1. cpu_ctxt is fine, as Xen checks that on context switch. - * 2. fpu_ctxt is fine, as it can't hurt Xen. - * 3. trap_ctxt needs the code selectors checked. - * 4. fast_trap_idx is checked by Xen. - * 5. ldt base must be page-aligned, no more than 8192 ents, ... - * 6. gdt already done, and further checking is done by Xen. - * 7. check that guestos_ss is safe. - * 8. pt_base is already done. - * 9. debugregs are checked by Xen. - * 10. callback code selectors need checking. - */ - for ( i = 0; i < 256; i++ ) { - ctxt.trap_ctxt[i].vector = i; - if ( (ctxt.trap_ctxt[i].cs & 3) == 0 ) - ctxt.trap_ctxt[i].cs = FLAT_GUESTOS_CS; - } - if ( (ctxt.guestos_ss & 3) == 0 ){ - ctxt.guestos_ss = FLAT_GUESTOS_DS; - } - if ( (ctxt.event_callback_cs & 3) == 0 ){ - ctxt.event_callback_cs = FLAT_GUESTOS_CS; - } - if ( (ctxt.failsafe_callback_cs & 3) == 0 ){ - ctxt.failsafe_callback_cs = FLAT_GUESTOS_CS; - } - if ( ((ctxt.ldt_base & (PAGE_SIZE - 1)) != 0) || - (ctxt.ldt_ents > 8192) || - (ctxt.ldt_base > HYPERVISOR_VIRT_START) || - ((ctxt.ldt_base + ctxt.ldt_ents*8) > HYPERVISOR_VIRT_START) ) - { - xcio_error(ioctxt, "Bad LDT base or size"); - goto out; - } - - op.cmd = DOM0_BUILDDOMAIN; - op.u.builddomain.domain = (domid_t)dom; - op.u.builddomain.ctxt = &ctxt; - rc = do_dom0_op(xc_handle, &op); - - /* don't start the domain as we have console etc to set up */ - - if( rc == 0 ) { - /* Success: print the domain id. */ - xcio_info(ioctxt, "DOM=%lu\n", dom); - return 0; - } - - - out: - if ( (rc != 0) && (dom != 0) ){ - xc_domain_destroy(xc_handle, dom); - } - if ( mmu != NULL ){ - free(mmu); - } - if ( pm_handle >= 0 ){ - (void)close_pfn_mapper(pm_handle); - } - if ( pfn_to_mfn_table != NULL ){ - free(pfn_to_mfn_table); - } - if ( pfn_type != NULL ){ - free(pfn_type); - } - - if ( rc == 0 ){ - ioctxt->domain = dom; - } - DPRINTF("Restore exit with rc=%d\n",rc); - return rc; -} diff --git a/tools/xc/lib/xc_linux_save.c b/tools/xc/lib/xc_linux_save.c deleted file mode 100644 index 44ffb6bb5f..0000000000 --- a/tools/xc/lib/xc_linux_save.c +++ /dev/null @@ -1,840 +0,0 @@ -/****************************************************************************** - * xc_linux_save.c - * - * Save the state of a running Linux session. - * - * Copyright (c) 2003, K A Fraser. - */ - -#include -#include "xc_private.h" -#include - -#define BATCH_SIZE 1024 /* 1024 pages (4MB) at a time */ - -#define DEBUG 0 -#define DDEBUG 0 - -#if DEBUG -#define DPRINTF(_f, _a...) printf ( _f , ## _a ) -#else -#define DPRINTF(_f, _a...) ((void)0) -#endif - -#if DDEBUG -#define DDPRINTF(_f, _a...) printf ( _f , ## _a ) -#else -#define DDPRINTF(_f, _a...) ((void)0) -#endif - -/* - * Returns TRUE if the given machine frame number has a unique mapping - * in the guest's pseudophysical map. - * 0x80000000-3 mark the shared_info, and blk/net rings - */ -#define MFN_IS_IN_PSEUDOPHYS_MAP(_mfn) \ - (((_mfn) < (1024*1024)) && \ - (((live_mfn_to_pfn_table[_mfn] < nr_pfns) && \ - (live_pfn_to_mfn_table[live_mfn_to_pfn_table[_mfn]] == (_mfn))) || \ - ((live_mfn_to_pfn_table[_mfn] >= 0x80000000) && \ - (live_mfn_to_pfn_table[_mfn] <= 0x80000003)) || \ - (live_pfn_to_mfn_table[live_mfn_to_pfn_table[_mfn]] == 0x80000004))) - -/* Returns TRUE if MFN is successfully converted to a PFN. */ -#define translate_mfn_to_pfn(_pmfn) \ -({ \ - unsigned long mfn = *(_pmfn); \ - int _res = 1; \ - if ( !MFN_IS_IN_PSEUDOPHYS_MAP(mfn) ) \ - _res = 0; \ - else \ - *(_pmfn) = live_mfn_to_pfn_table[mfn]; \ - _res; \ -}) - -static inline int test_bit ( int nr, volatile void * addr) -{ - return (((unsigned long*)addr)[nr/(sizeof(unsigned long)*8)] >> - (nr % (sizeof(unsigned long)*8))) & 1; -} - -static inline void clear_bit ( int nr, volatile void * addr) -{ - ((unsigned long*)addr)[nr/(sizeof(unsigned long)*8)] &= - ~(1 << (nr % (sizeof(unsigned long)*8) ) ); -} - -static inline void set_bit ( int nr, volatile void * addr) -{ - ((unsigned long*)addr)[nr/(sizeof(unsigned long)*8)] |= - (1 << (nr % (sizeof(unsigned long)*8) ) ); -} - -/* Returns the hamming weight (i.e. the number of bits set) in a N-bit word */ -static inline unsigned int hweight32(unsigned int w) -{ - unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555); - res = (res & 0x33333333) + ((res >> 2) & 0x33333333); - res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F); - res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF); - return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF); -} - -static inline int count_bits ( int nr, volatile void *addr) -{ - int i, count = 0; - unsigned long *p = (unsigned long *)addr; - /* We know that the array is padded to unsigned long. */ - for(i=0;ioder 15->4 16->4 17->5 */ - /* 512MB domain, 128k pages, order 17 */ - - /* - QPONMLKJIHGFEDCBA - QPONMLKJIH - GFEDCBA - */ - - /* - QPONMLKJIHGFEDCBA - EDCBA - QPONM - LKJIHGF - */ - - do { i = ((i>>(order_nr-10)) | ( i<<10 ) ) & ((1<= nr ); /* this won't ever loop if nr is a power of 2 */ - - return i; -} - -static long long tv_to_us( struct timeval *new ) -{ - return (new->tv_sec * 1000000) + new->tv_usec; -} - -static long long llgettimeofday() -{ - struct timeval now; - gettimeofday(&now, NULL); - return tv_to_us(&now); -} - -static long long tv_delta( struct timeval *new, struct timeval *old ) -{ - return ((new->tv_sec - old->tv_sec)*1000000 ) + - (new->tv_usec - old->tv_usec); -} - -static int print_stats( int xc_handle, u32 domid, - int pages_sent, xc_shadow_control_stats_t *stats, - int print ) -{ - static struct timeval wall_last; - static long long d0_cpu_last; - static long long d1_cpu_last; - - struct timeval wall_now; - long long wall_delta; - long long d0_cpu_now, d0_cpu_delta; - long long d1_cpu_now, d1_cpu_delta; - - gettimeofday(&wall_now, NULL); - - d0_cpu_now = xc_domain_get_cpu_usage( xc_handle, 0 )/1000; - d1_cpu_now = xc_domain_get_cpu_usage( xc_handle, domid )/1000; - - if ( (d0_cpu_now == -1) || (d1_cpu_now == -1) ) - printf("ARRHHH!!\n"); - - wall_delta = tv_delta(&wall_now,&wall_last)/1000; - - if ( wall_delta == 0 ) wall_delta = 1; - - d0_cpu_delta = (d0_cpu_now - d0_cpu_last)/1000; - d1_cpu_delta = (d1_cpu_now - d1_cpu_last)/1000; - - if ( print ) - printf("delta %lldms, dom0 %d%%, target %d%%, sent %dMb/s, " - "dirtied %dMb/s\n", - wall_delta, - (int)((d0_cpu_delta*100)/wall_delta), - (int)((d1_cpu_delta*100)/wall_delta), - (int)((pages_sent*PAGE_SIZE*8)/(wall_delta*1000)), - (int)((stats->dirty_count*PAGE_SIZE*8)/(wall_delta*1000))); - - d0_cpu_last = d0_cpu_now; - d1_cpu_last = d1_cpu_now; - wall_last = wall_now; - - return 0; -} - -/** Write the vmconfig string. - * It is stored as a 4-byte count 'n' followed by n bytes. - * - * @param ioctxt i/o context - * @return 0 on success, non-zero on error. - */ -static int write_vmconfig(XcIOContext *ioctxt){ - int err = -1; - if(xcio_write(ioctxt, &ioctxt->vmconfig_n, sizeof(ioctxt->vmconfig_n))) goto exit; - if(xcio_write(ioctxt, ioctxt->vmconfig, ioctxt->vmconfig_n)) goto exit; - err = 0; - exit: - return err; -} - -static int analysis_phase( int xc_handle, u32 domid, - int nr_pfns, unsigned long *arr ) -{ - long long start, now; - xc_shadow_control_stats_t stats; - - start = llgettimeofday(); - - while ( 0 ) - { - int i; - - xc_shadow_control( xc_handle, domid, - DOM0_SHADOW_CONTROL_OP_CLEAN2, - arr, nr_pfns, NULL); - printf("#Flush\n"); - for ( i = 0; i < 100; i++ ) - { - usleep(10000); - now = llgettimeofday(); - xc_shadow_control( xc_handle, domid, - DOM0_SHADOW_CONTROL_OP_PEEK, - NULL, 0, &stats); - - printf("now= %lld faults= %ld dirty= %ld dirty_net= %ld " - "dirty_block= %ld\n", - ((now-start)+500)/1000, - stats.fault_count, stats.dirty_count, - stats.dirty_net_count, stats.dirty_block_count); - } - } - - return -1; -} - -int xc_linux_save(int xc_handle, XcIOContext *ioctxt) -{ - dom0_op_t op; - int rc = 1, i, j, k, last_iter, iter = 0; - unsigned long mfn; - u32 domid = ioctxt->domain; - int live = (ioctxt->flags & XCFLAGS_LIVE); - int debug = (ioctxt->flags & XCFLAGS_DEBUG); - int sent_last_iter, skip_this_iter; - - /* Important tuning parameters */ - int max_iters = 29; /* limit us to 30 times round loop */ - int max_factor = 3; /* never send more than 3x nr_pfns */ - - /* The new domain's shared-info frame number. */ - unsigned long shared_info_frame; - - /* A copy of the CPU context of the guest. */ - full_execution_context_t ctxt; - - /* A copy of the domain's name. */ - char name[MAX_DOMAIN_NAME]; - - /* A table containg the type of each PFN (/not/ MFN!). */ - unsigned long *pfn_type = NULL; - unsigned long *pfn_batch = NULL; - - /* A temporary mapping, and a copy, of one frame of guest memory. */ - unsigned long page[1024]; - - /* A copy of the pfn-to-mfn table frame list. */ - unsigned long *live_pfn_to_mfn_frame_list; - unsigned long pfn_to_mfn_frame_list[1024]; - - /* Live mapping of the table mapping each PFN to its current MFN. */ - unsigned long *live_pfn_to_mfn_table = NULL; - /* Live mapping of system MFN to PFN table. */ - unsigned long *live_mfn_to_pfn_table = NULL; - - /* Live mapping of shared info structure */ - unsigned long *live_shinfo; - - /* base of the region in which domain memory is mapped */ - unsigned char *region_base = NULL; - - /* A temporary mapping, and a copy, of the guest's suspend record. */ - suspend_record_t *p_srec; - - /* number of pages we're dealing with */ - unsigned long nr_pfns; - - /* power of 2 order of nr_pfns */ - int order_nr; - - /* bitmap of pages: - - that should be sent this iteration (unless later marked as skip); - - to skip this iteration because already dirty; - - to fixup by sending at the end if not already resent; */ - unsigned long *to_send, *to_skip, *to_fix; - - xc_shadow_control_stats_t stats; - - int needed_to_fix = 0; - int total_sent = 0; - - if (mlock(&ctxt, sizeof(ctxt))) { - xcio_perror(ioctxt, "Unable to mlock ctxt"); - return 1; - } - - /* Ensure that the domain exists, and that it is stopped. */ - if ( xc_domain_pause(xc_handle, domid) ){ - xcio_perror(ioctxt, "Could not pause domain"); - goto out; - } - - if ( xc_domain_getfullinfo( xc_handle, domid, &op, &ctxt) ) - { - PERROR("Could not get full domain info"); - goto out; - } - memcpy(name, op.u.getdomaininfo.name, sizeof(name)); - shared_info_frame = op.u.getdomaininfo.shared_info_frame; - - /* A cheesy test to see whether the domain contains valid state. */ - if ( ctxt.pt_base == 0 ){ - xcio_error(ioctxt, "Domain is not in a valid Linux guest OS state"); - goto out; - } - - /* Map the suspend-record MFN to pin it. The page must be owned by - domid for this to succeed. */ - p_srec = mfn_mapper_map_single(xc_handle, domid, - sizeof(*p_srec), PROT_READ, - ctxt.cpu_ctxt.esi); - if (!p_srec){ - xcio_error(ioctxt, "Couldn't map state record"); - goto out; - } - - nr_pfns = p_srec->nr_pfns; - - /* cheesy sanity check */ - if ( nr_pfns > 1024*1024 ){ - xcio_error(ioctxt, "Invalid state record -- pfn count out of range"); - goto out; - } - - /* the pfn_to_mfn_frame_list fits in a single page */ - live_pfn_to_mfn_frame_list = - mfn_mapper_map_single(xc_handle, domid, - PAGE_SIZE, PROT_READ, - p_srec->pfn_to_mfn_frame_list ); - - if (!live_pfn_to_mfn_frame_list){ - xcio_error(ioctxt, "Couldn't map pfn_to_mfn_frame_list"); - goto out; - } - - /* Track the mfn_to_pfn table down from the domains PT */ - { - unsigned long *pgd; - unsigned long mfn_to_pfn_table_start_mfn; - - pgd = mfn_mapper_map_single(xc_handle, domid, - PAGE_SIZE, PROT_READ, - ctxt.pt_base>>PAGE_SHIFT); - - mfn_to_pfn_table_start_mfn = - pgd[HYPERVISOR_VIRT_START>>L2_PAGETABLE_SHIFT]>>PAGE_SHIFT; - - live_mfn_to_pfn_table = - mfn_mapper_map_single(xc_handle, ~0UL, - PAGE_SIZE*1024, PROT_READ, - mfn_to_pfn_table_start_mfn ); - } - - /* Map all the frames of the pfn->mfn table. For migrate to succeed, - the guest must not change which frames are used for this purpose. - (its not clear why it would want to change them, and we'll be OK - from a safety POV anyhow. */ - - live_pfn_to_mfn_table = mfn_mapper_map_batch(xc_handle, domid, - PROT_READ, - live_pfn_to_mfn_frame_list, - (nr_pfns+1023)/1024 ); - if( !live_pfn_to_mfn_table ){ - xcio_perror(ioctxt, "Couldn't map pfn_to_mfn table"); - goto out; - } - - - /* Canonicalise the pfn-to-mfn table frame-number list. */ - memcpy( pfn_to_mfn_frame_list, live_pfn_to_mfn_frame_list, PAGE_SIZE ); - for ( i = 0; i < nr_pfns; i += 1024 ){ - if ( !translate_mfn_to_pfn(&pfn_to_mfn_frame_list[i/1024]) ){ - xcio_error(ioctxt, "Frame # in pfn-to-mfn frame list is not in pseudophys"); - goto out; - } - } - - /* At this point, we can start the domain again if we're doing a - live suspend */ - - if( live ){ - if ( xc_shadow_control( xc_handle, domid, - DOM0_SHADOW_CONTROL_OP_ENABLE_LOGDIRTY, - NULL, 0, NULL ) < 0 ) { - xcio_error(ioctxt, "Couldn't enable shadow mode"); - goto out; - } - - if ( xc_domain_unpause(xc_handle, domid) < 0 ){ - xcio_error(ioctxt, "Couldn't unpause domain"); - goto out; - } - - last_iter = 0; - sent_last_iter = 1<<20; /* 4GB of pages */ - } else{ - last_iter = 1; - } - - /* calculate the power of 2 order of nr_pfns, e.g. - 15->4 16->4 17->5 */ - for( i=nr_pfns-1, order_nr=0; i ; i>>=1, order_nr++ ); - - /* Setup to_send bitmap */ - { - int sz = (nr_pfns/8) + 8; /* includes slop at end of array */ - - to_send = malloc( sz ); - to_fix = calloc( 1, sz ); - to_skip = malloc( sz ); - - if (!to_send || !to_fix || !to_skip){ - xcio_error(ioctxt, "Couldn't allocate to_send array"); - goto out; - } - - memset( to_send, 0xff, sz ); - - if ( mlock( to_send, sz ) ){ - xcio_perror(ioctxt, "Unable to mlock to_send"); - return 1; - } - - /* (to fix is local only) */ - - if ( mlock( to_skip, sz ) ){ - xcio_perror(ioctxt, "Unable to mlock to_skip"); - return 1; - } - - } - - analysis_phase( xc_handle, domid, nr_pfns, to_skip ); - - /* We want zeroed memory so use calloc rather than malloc. */ - pfn_type = calloc(BATCH_SIZE, sizeof(unsigned long)); - pfn_batch = calloc(BATCH_SIZE, sizeof(unsigned long)); - - if ( (pfn_type == NULL) || (pfn_batch == NULL) ){ - errno = ENOMEM; - goto out; - } - - if ( mlock( pfn_type, BATCH_SIZE * sizeof(unsigned long) ) ){ - xcio_error(ioctxt, "Unable to mlock"); - goto out; - } - - - /* - * Quick belt and braces sanity check. - */ -#if DEBUG - for ( i = 0; i < nr_pfns; i++ ){ - mfn = live_pfn_to_mfn_table[i]; - - if( (live_mfn_to_pfn_table[mfn] != i) && (mfn != 0x80000004) ) - printf("i=0x%x mfn=%x live_mfn_to_pfn_table=%x\n", - i,mfn,live_mfn_to_pfn_table[mfn]); - } -#endif - - /* Map the shared info frame */ - live_shinfo = mfn_mapper_map_single(xc_handle, domid, - PAGE_SIZE, PROT_READ, - shared_info_frame); - - if (!live_shinfo){ - xcio_error(ioctxt, "Couldn't map live_shinfo"); - goto out; - } - - /* Start writing out the saved-domain record. */ - - if ( xcio_write(ioctxt, "LinuxGuestRecord", 16) || - xcio_write(ioctxt, name, sizeof(name)) || - xcio_write(ioctxt, &nr_pfns, sizeof(unsigned long)) || - xcio_write(ioctxt, pfn_to_mfn_frame_list, PAGE_SIZE) ){ - xcio_error(ioctxt, "Error writing header"); - goto out; - } - if(write_vmconfig(ioctxt)){ - xcio_error(ioctxt, "Error writing vmconfig"); - goto out; - } - - print_stats( xc_handle, domid, 0, &stats, 0 ); - - /* Now write out each data page, canonicalising page tables as we go... */ - - while(1){ - unsigned int prev_pc, sent_this_iter, N, batch; - - iter++; - sent_this_iter = 0; - skip_this_iter = 0; - prev_pc = 0; - N=0; - - xcio_info(ioctxt, "Saving memory pages: iter %d 0%%", iter); - - while( N < nr_pfns ){ - unsigned int this_pc = (N * 100) / nr_pfns; - - if ( (this_pc - prev_pc) >= 5 ){ - xcio_info(ioctxt, "\b\b\b\b%3d%%", this_pc); - prev_pc = this_pc; - } - - /* slightly wasteful to peek the whole array evey time, - but this is fast enough for the moment. */ - - if ( !last_iter && - xc_shadow_control(xc_handle, domid, - DOM0_SHADOW_CONTROL_OP_PEEK, - to_skip, nr_pfns, NULL) != nr_pfns ) { - xcio_error(ioctxt, "Error peeking shadow bitmap"); - goto out; - } - - - /* load pfn_type[] with the mfn of all the pages we're doing in - this batch. */ - - for ( batch = 0; batch < BATCH_SIZE && N < nr_pfns ; N++ ) - { - int n = permute(N, nr_pfns, order_nr ); - - if ( 0 && debug ) { - fprintf(stderr,"%d pfn= %08lx mfn= %08lx %d " - " [mfn]= %08lx\n", - iter, (unsigned long)n, live_pfn_to_mfn_table[n], - test_bit(n,to_send), - live_mfn_to_pfn_table[live_pfn_to_mfn_table[n]& - 0xFFFFF]); - } - - if ( !last_iter && - test_bit(n, to_send) && - test_bit(n, to_skip) ) { - skip_this_iter++; /* stats keeping */ - } - - if ( !((test_bit(n, to_send) && !test_bit(n, to_skip)) || - (test_bit(n, to_send) && last_iter) || - (test_bit(n, to_fix) && last_iter)) ) { - continue; - } - - /* we get here if: - 1. page is marked to_send & hasn't already been re-dirtied - 2. (ignore to_skip in last iteration) - 3. add in pages that still need fixup (net bufs) - */ - - pfn_batch[batch] = n; - pfn_type[batch] = live_pfn_to_mfn_table[n]; - - if( pfn_type[batch] == 0x80000004 ){ - /* not currently in pusedo-physical map -- set bit - in to_fix that we must send this page in last_iter - unless its sent sooner anyhow */ - - set_bit( n, to_fix ); - if( iter>1 ) - DDPRINTF("netbuf race: iter %d, pfn %lx. mfn %lx\n", - iter,n,pfn_type[batch]); - continue; - } - - if ( last_iter && - test_bit(n, to_fix) && - !test_bit(n, to_send) ) - { - needed_to_fix++; - DPRINTF("Fix! iter %d, pfn %lx. mfn %lx\n", - iter,n,pfn_type[batch]); - } - - clear_bit(n, to_fix); - - batch++; - } - - DDPRINTF("batch %d:%d (n=%d)\n", iter, batch, n); - - if ( batch == 0 ) - goto skip; /* vanishingly unlikely... */ - - if ( (region_base = mfn_mapper_map_batch(xc_handle, domid, - PROT_READ, - pfn_type, - batch)) == 0 ){ - xcio_perror(ioctxt, "map batch failed"); - goto out; - } - - if ( get_pfn_type_batch(xc_handle, domid, batch, pfn_type) ){ - xcio_error(ioctxt, "get_pfn_type_batch failed"); - goto out; - } - - for ( j = 0; j < batch; j++ ){ - if ( (pfn_type[j] & LTAB_MASK) == XTAB ){ - DDPRINTF("type fail: page %i mfn %08lx\n",j,pfn_type[j]); - continue; - } - - if ( 0 && debug ) - fprintf(stderr, "%d pfn= %08lx mfn= %08lx [mfn]= %08lx" - " sum= %08lx\n", - iter, - (pfn_type[j] & LTAB_MASK) | pfn_batch[j], - pfn_type[j], - live_mfn_to_pfn_table[pfn_type[j]&(~LTAB_MASK)], - csum_page(region_base + (PAGE_SIZE*j))); - - /* canonicalise mfn->pfn */ - pfn_type[j] = (pfn_type[j] & LTAB_MASK) | pfn_batch[j]; - } - - if ( xcio_write(ioctxt, &batch, sizeof(int) ) ){ - xcio_error(ioctxt, "Error when writing to state file (2)"); - goto out; - } - - if ( xcio_write(ioctxt, pfn_type, sizeof(unsigned long)*j ) ){ - xcio_error(ioctxt, "Error when writing to state file (3)"); - goto out; - } - - /* entering this loop, pfn_type is now in pfns (Not mfns) */ - for( j = 0; j < batch; j++ ){ - /* write out pages in batch */ - if( (pfn_type[j] & LTAB_MASK) == XTAB){ - DDPRINTF("SKIP BOGUS page %i mfn %08lx\n",j,pfn_type[j]); - continue; - } - - if ( ((pfn_type[j] & LTAB_MASK) == L1TAB) || - ((pfn_type[j] & LTAB_MASK) == L2TAB) ){ - memcpy(page, region_base + (PAGE_SIZE*j), PAGE_SIZE); - - for ( k = 0; - k < (((pfn_type[j] & LTAB_MASK) == L2TAB) ? - (HYPERVISOR_VIRT_START >> L2_PAGETABLE_SHIFT) : - 1024); - k++ ){ - unsigned long pfn; - - if ( !(page[k] & _PAGE_PRESENT) ) - continue; - - mfn = page[k] >> PAGE_SHIFT; - pfn = live_mfn_to_pfn_table[mfn]; - - if ( !MFN_IS_IN_PSEUDOPHYS_MAP(mfn) ) - { - /* I don't think this should ever happen */ - printf("FNI %d : [%08lx,%d] pte=%08lx, " - "mfn=%08lx, pfn=%08lx [mfn]=%08lx\n", - j, pfn_type[j], k, - page[k], mfn, live_mfn_to_pfn_table[mfn], - (live_mfn_to_pfn_table[mfn]>28, - j,i,mfn,k,page[k],page[k]>>PAGE_SHIFT); -#endif - - } /* end of page table rewrite for loop */ - - if ( xcio_write(ioctxt, page, PAGE_SIZE) ){ - xcio_error(ioctxt, "Error when writing to state file (4)"); - goto out; - } - - } /* end of it's a PT page */ else { /* normal page */ - - if ( xcio_write(ioctxt, region_base + (PAGE_SIZE*j), - PAGE_SIZE) ){ - xcio_error(ioctxt, "Error when writing to state file (5)"); - goto out; - } - } - } /* end of the write out for this batch */ - - sent_this_iter += batch; - - } /* end of this while loop for this iteration */ - - munmap(region_base, batch*PAGE_SIZE); - - skip: - - total_sent += sent_this_iter; - - xcio_info(ioctxt, "\r %d: sent %d, skipped %d, ", - iter, sent_this_iter, skip_this_iter ); - - if ( last_iter ) { - print_stats( xc_handle, domid, sent_this_iter, &stats, 1); - - xcio_info(ioctxt, "Total pages sent= %d (%.2fx)\n", - total_sent, ((float)total_sent)/nr_pfns ); - xcio_info(ioctxt, "(of which %d were fixups)\n", needed_to_fix ); - } - - if (last_iter && debug){ - int minusone = -1; - memset( to_send, 0xff, (nr_pfns+8)/8 ); - debug = 0; - printf("Entering debug resend-all mode\n"); - - /* send "-1" to put receiver into debug mode */ - if ( xcio_write(ioctxt, &minusone, sizeof(int)) ) - { - xcio_error(ioctxt, "Error when writing to state file (6)"); - goto out; - } - - continue; - } - - if ( last_iter ) break; - - if ( live ) - { - if ( - /* ( sent_this_iter > (sent_last_iter * 0.95) ) || */ - (iter >= max_iters) || - (sent_this_iter+skip_this_iter < 50) || - (total_sent > nr_pfns*max_factor) ) - { - DPRINTF("Start last iteration\n"); - last_iter = 1; - - xc_domain_pause( xc_handle, domid ); - } - - if ( xc_shadow_control( xc_handle, domid, - DOM0_SHADOW_CONTROL_OP_CLEAN2, - to_send, nr_pfns, &stats ) != nr_pfns ) - { - xcio_error(ioctxt, "Error flushing shadow PT"); - goto out; - } - - sent_last_iter = sent_this_iter; - - print_stats( xc_handle, domid, sent_this_iter, &stats, 1); - - } - - - } /* end of while 1 */ - - DPRINTF("All memory is saved\n"); - - /* Success! */ - rc = 0; - - /* Zero terminate */ - if ( xcio_write(ioctxt, &rc, sizeof(int)) ) - { - xcio_error(ioctxt, "Error when writing to state file (6)"); - goto out; - } - - /* Get the final execution context */ - if ( xc_domain_getfullinfo( xc_handle, domid, &op, &ctxt) ) - { - xcio_perror(ioctxt, "Could not get full domain info"); - goto out; - } - - /* Canonicalise the suspend-record frame number. */ - if ( !translate_mfn_to_pfn(&ctxt.cpu_ctxt.esi) ){ - xcio_error(ioctxt, "State record is not in range of pseudophys map"); - goto out; - } - - /* Canonicalise each GDT frame number. */ - for ( i = 0; i < ctxt.gdt_ents; i += 512 ) { - if ( !translate_mfn_to_pfn(&ctxt.gdt_frames[i]) ) { - xcio_error(ioctxt, "GDT frame is not in range of pseudophys map"); - goto out; - } - } - - /* Canonicalise the page table base pointer. */ - if ( !MFN_IS_IN_PSEUDOPHYS_MAP(ctxt.pt_base >> PAGE_SHIFT) ) { - xcio_error(ioctxt, "PT base is not in range of pseudophys map"); - goto out; - } - ctxt.pt_base = live_mfn_to_pfn_table[ctxt.pt_base >> PAGE_SHIFT] << - PAGE_SHIFT; - - if ( xcio_write(ioctxt, &ctxt, sizeof(ctxt)) || - xcio_write(ioctxt, live_shinfo, PAGE_SIZE) ) { - xcio_error(ioctxt, "Error when writing to state file (1)"); - goto out; - } - munmap(live_shinfo, PAGE_SIZE); - - out: - if ( pfn_type != NULL ) free(pfn_type); - DPRINTF("Save exit rc=%d\n",rc); - return !!rc; - -} diff --git a/tools/xc/lib/xc_misc.c b/tools/xc/lib/xc_misc.c deleted file mode 100644 index 0019ffe96b..0000000000 --- a/tools/xc/lib/xc_misc.c +++ /dev/null @@ -1,87 +0,0 @@ -/****************************************************************************** - * xc_misc.c - * - * Miscellaneous control interface functions. - */ - -#include "xc_private.h" - -int xc_interface_open(void) -{ - int fd = open("/proc/xen/privcmd", O_RDWR); - if ( fd == -1 ) - PERROR("Could not obtain handle on privileged command interface"); - return fd; -} - -int xc_interface_close(int xc_handle) -{ - return close(xc_handle); -} - - -#define CONSOLE_RING_CLEAR 1 - -int xc_readconsolering(int xc_handle, - char *str, - unsigned int max_chars, - int clear) -{ - int ret; - dom0_op_t op; - - op.cmd = DOM0_READCONSOLE; - op.u.readconsole.str = (unsigned long)str; - op.u.readconsole.count = max_chars; - op.u.readconsole.cmd = clear ? CONSOLE_RING_CLEAR : 0; - - if ( (ret = mlock(str, max_chars)) != 0 ) - return ret; - - if ( (ret = do_dom0_op(xc_handle, &op)) >= 0 ) - str[ret] = '\0'; - - (void)munlock(str, max_chars); - - return ret; -} - - -int xc_physinfo(int xc_handle, - xc_physinfo_t *put_info) -{ - int ret; - dom0_op_t op; - dom0_physinfo_t *got_info = &op.u.physinfo; - - op.cmd = DOM0_PHYSINFO; - op.interface_version = DOM0_INTERFACE_VERSION; - - if((ret = do_dom0_op(xc_handle, &op))) return ret; - - put_info->ht_per_core = got_info->ht_per_core; - put_info->cores = got_info->cores; - put_info->total_pages = got_info->total_pages; - put_info->free_pages = got_info->free_pages; - put_info->cpu_khz = got_info->cpu_khz; - - return 0; -} - - -int xc_sched_id(int xc_handle, - int *sched_id) -{ - int ret; - dom0_op_t op; - - op.cmd = DOM0_SCHED_ID; - op.interface_version = DOM0_INTERFACE_VERSION; - - if((ret = do_dom0_op(xc_handle, &op))) return ret; - - *sched_id = op.u.sched_id.sched_id; - - return 0; -} - diff --git a/tools/xc/lib/xc_netbsd_build.c b/tools/xc/lib/xc_netbsd_build.c deleted file mode 100644 index 04a47b5068..0000000000 --- a/tools/xc/lib/xc_netbsd_build.c +++ /dev/null @@ -1,705 +0,0 @@ -/****************************************************************************** - * xc_netbsd_build.c - */ - -#include "xc_private.h" -#define ELFSIZE 32 /* XXX */ -#include "xc_elf.h" -#include - -#ifdef DEBUG -#define DPRINTF(x) printf x -#else -#define DPRINTF(x) -#endif - -static int loadelfimage(gzFile, int, unsigned long *, unsigned long, - unsigned long *, unsigned long *, - unsigned long *, unsigned long *); - -#define ELFROUND (ELFSIZE / 8) - -#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED) -#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER) - -static long get_tot_pages(int xc_handle, u32 domid) -{ - dom0_op_t op; - op.cmd = DOM0_GETDOMAININFO; - op.u.getdomaininfo.domain = (domid_t)domid; - op.u.getdomaininfo.ctxt = NULL; - return (do_dom0_op(xc_handle, &op) < 0) ? - -1 : op.u.getdomaininfo.tot_pages; -} - -static int get_pfn_list(int xc_handle, - u32 domid, - unsigned long *pfn_buf, - unsigned long max_pfns) -{ - dom0_op_t op; - int ret; - op.cmd = DOM0_GETMEMLIST; - op.u.getmemlist.domain = (domid_t)domid; - op.u.getmemlist.max_pfns = max_pfns; - op.u.getmemlist.buffer = pfn_buf; - - if ( mlock(pfn_buf, max_pfns * sizeof(unsigned long)) != 0 ) - return -1; - - ret = do_dom0_op(xc_handle, &op); - - (void)munlock(pfn_buf, max_pfns * sizeof(unsigned long)); - - return (ret < 0) ? -1 : op.u.getmemlist.num_pfns; -} - -static int setup_guestos(int xc_handle, - u32 dom, - gzFile kernel_gfd, - unsigned long tot_pages, - unsigned long *virt_startinfo_addr, - unsigned long *virt_load_addr, - full_execution_context_t *ctxt, - const char *cmdline, - unsigned long shared_info_frame, - unsigned int control_evtchn) -{ - l1_pgentry_t *vl1tab=NULL, *vl1e=NULL; - l2_pgentry_t *vl2tab=NULL, *vl2e=NULL; - unsigned long *page_array = NULL; - int alloc_index, num_pt_pages; - unsigned long l2tab; - unsigned long l1tab; - unsigned long count, pt_start; - unsigned long symtab_addr = 0, symtab_len = 0; - extended_start_info_t *start_info; - shared_info_t *shared_info; - unsigned long ksize; - mmu_t *mmu = NULL; - int pm_handle, i; - - if ( (pm_handle = init_pfn_mapper((domid_t)dom)) < 0 ) - goto error_out; - - if ( (page_array = malloc(tot_pages * sizeof(unsigned long))) == NULL ) - { - PERROR("Could not allocate memory"); - goto error_out; - } - - if ( get_pfn_list(xc_handle, dom, page_array, tot_pages) != tot_pages ) - { - PERROR("Could not get the page frame list"); - goto error_out; - } - - if (loadelfimage(kernel_gfd, pm_handle, page_array, tot_pages, - virt_load_addr, &ksize, &symtab_addr, &symtab_len)) - goto error_out; - - /* ksize is kernel-image size rounded up to a page boundary. */ - - alloc_index = tot_pages - 1; - - /* Count bottom-level PTs, rounding up. */ - num_pt_pages = (l1_table_offset(*virt_load_addr) + tot_pages + 1023) - / 1024; - - /* We must also count the page directory. */ - num_pt_pages++; - - /* Index of first PT page. */ - pt_start = tot_pages - num_pt_pages; - - /* - * First allocate page for page dir. Allocation goes backwards from the end - * of the allocated physical address space. - */ - l2tab = page_array[alloc_index] << PAGE_SHIFT; - alloc_index--; - ctxt->pt_base = l2tab; - - if ( (mmu = init_mmu_updates(xc_handle, dom)) == NULL ) - goto error_out; - - /* Initialise the page tables. */ - if ( (vl2tab = map_pfn_writeable(pm_handle, l2tab >> PAGE_SHIFT)) == NULL ) - goto error_out; - memset(vl2tab, 0, PAGE_SIZE); - vl2e = &vl2tab[l2_table_offset(*virt_load_addr)]; - for ( count = 0; count < tot_pages; count++ ) - { - if ( ((unsigned long)vl1e & (PAGE_SIZE-1)) == 0 ) - { - l1tab = page_array[alloc_index--] << PAGE_SHIFT; - if ( vl1tab != NULL ) - unmap_pfn(pm_handle, vl1tab); - if ( (vl1tab = map_pfn_writeable(pm_handle, - l1tab >> PAGE_SHIFT)) == NULL ) - goto error_out; - memset(vl1tab, 0, PAGE_SIZE); - vl1e = &vl1tab[l1_table_offset(*virt_load_addr + - (count<= pt_start ) - *vl1e &= ~_PAGE_RW; - vl1e++; - - if ( add_mmu_update(xc_handle, mmu, - (page_array[count] << PAGE_SHIFT) | - MMU_MACHPHYS_UPDATE, count) ) - goto error_out; - } - unmap_pfn(pm_handle, vl1tab); - unmap_pfn(pm_handle, vl2tab); - - /* - * Pin down l2tab addr as page dir page - causes hypervisor to provide - * correct protection for the page - */ - if ( add_mmu_update(xc_handle, mmu, - l2tab | MMU_EXTENDED_COMMAND, MMUEXT_PIN_L2_TABLE) ) - goto error_out; - - *virt_startinfo_addr = - *virt_load_addr + ((alloc_index-1) << PAGE_SHIFT); - - start_info = map_pfn_writeable(pm_handle, page_array[alloc_index-1]); - memset(start_info, 0, sizeof(*start_info)); - start_info->pt_base = *virt_load_addr + ((tot_pages-1) << PAGE_SHIFT); - start_info->mod_start = symtab_addr; - start_info->mod_len = symtab_len; - start_info->nr_pages = tot_pages; - start_info->shared_info = shared_info_frame << PAGE_SHIFT; - start_info->flags = 0; - start_info->domain_controller_evtchn = control_evtchn; - strncpy(start_info->cmd_line, cmdline, MAX_CMDLINE); - start_info->cmd_line[MAX_CMDLINE-1] = '\0'; - unmap_pfn(pm_handle, start_info); - - /* shared_info page starts its life empty. */ - shared_info = map_pfn_writeable(pm_handle, shared_info_frame); - memset(shared_info, 0, PAGE_SIZE); - /* Mask all upcalls... */ - for ( i = 0; i < MAX_VIRT_CPUS; i++ ) - shared_info->vcpu_data[i].evtchn_upcall_mask = 1; - unmap_pfn(pm_handle, shared_info); - - /* Send the page update requests down to the hypervisor. */ - if ( finish_mmu_updates(xc_handle, mmu) ) - goto error_out; - - free(mmu); - (void)close_pfn_mapper(pm_handle); - free(page_array); - return 0; - - error_out: - if ( mmu != NULL ) - free(mmu); - if ( pm_handle >= 0 ) - (void)close_pfn_mapper(pm_handle); - if ( page_array == NULL ) - free(page_array); - return -1; -} - -int xc_netbsd_build(int xc_handle, - u32 domid, - const char *image_name, - const char *cmdline, - unsigned int control_evtchn) -{ - dom0_op_t launch_op, op; - unsigned long load_addr; - long tot_pages; - int kernel_fd = -1; - gzFile kernel_gfd = NULL; - int rc, i; - full_execution_context_t st_ctxt, *ctxt = &st_ctxt; - unsigned long virt_startinfo_addr; - - if ( (tot_pages = get_tot_pages(xc_handle, domid)) < 0 ) - { - PERROR("Could not find total pages for domain"); - return 1; - } - - kernel_fd = open(image_name, O_RDONLY); - if ( kernel_fd < 0 ) - { - PERROR("Could not open kernel image"); - return 1; - } - - if ( (kernel_gfd = gzdopen(kernel_fd, "rb")) == NULL ) - { - PERROR("Could not allocate decompression state for state file"); - close(kernel_fd); - return 1; - } - - if ( mlock(&st_ctxt, sizeof(st_ctxt) ) ) - { - PERROR("Unable to mlock ctxt"); - return 1; - } - - op.cmd = DOM0_GETDOMAININFO; - op.u.getdomaininfo.domain = (domid_t)domid; - op.u.getdomaininfo.ctxt = ctxt; - if ( (do_dom0_op(xc_handle, &op) < 0) || - ((u32)op.u.getdomaininfo.domain != domid) ) - { - PERROR("Could not get info on domain"); - goto error_out; - } - if ( !(op.u.getdomaininfo.flags & DOMFLAGS_PAUSED) || - (op.u.getdomaininfo.ctxt->pt_base != 0) ) - { - ERROR("Domain is already constructed"); - goto error_out; - } - - if ( setup_guestos(xc_handle, domid, kernel_gfd, tot_pages, - &virt_startinfo_addr, - &load_addr, &st_ctxt, cmdline, - op.u.getdomaininfo.shared_info_frame, - control_evtchn) < 0 ) - { - ERROR("Error constructing guest OS"); - goto error_out; - } - - if ( kernel_fd >= 0 ) - close(kernel_fd); - if( kernel_gfd ) - gzclose(kernel_gfd); - - ctxt->flags = 0; - - /* - * Initial register values: - * DS,ES,FS,GS = FLAT_GUESTOS_DS - * CS:EIP = FLAT_GUESTOS_CS:start_pc - * SS:ESP = FLAT_GUESTOS_DS:start_stack - * ESI = start_info - * [EAX,EBX,ECX,EDX,EDI,EBP are zero] - * EFLAGS = IF | 2 (bit 1 is reserved and should always be 1) - */ - ctxt->cpu_ctxt.ds = FLAT_GUESTOS_DS; - ctxt->cpu_ctxt.es = FLAT_GUESTOS_DS; - ctxt->cpu_ctxt.fs = FLAT_GUESTOS_DS; - ctxt->cpu_ctxt.gs = FLAT_GUESTOS_DS; - ctxt->cpu_ctxt.ss = FLAT_GUESTOS_DS; - ctxt->cpu_ctxt.cs = FLAT_GUESTOS_CS; - ctxt->cpu_ctxt.eip = load_addr; - ctxt->cpu_ctxt.esp = virt_startinfo_addr; - ctxt->cpu_ctxt.esi = virt_startinfo_addr; - ctxt->cpu_ctxt.eflags = (1<<9) | (1<<2); - - /* FPU is set up to default initial state. */ - memset(ctxt->fpu_ctxt, 0, sizeof(ctxt->fpu_ctxt)); - - /* Virtual IDT is empty at start-of-day. */ - for ( i = 0; i < 256; i++ ) - { - ctxt->trap_ctxt[i].vector = i; - ctxt->trap_ctxt[i].cs = FLAT_GUESTOS_CS; - } - ctxt->fast_trap_idx = 0; - - /* No LDT. */ - ctxt->ldt_ents = 0; - - /* Use the default Xen-provided GDT. */ - ctxt->gdt_ents = 0; - - /* Ring 1 stack is the initial stack. */ - ctxt->guestos_ss = FLAT_GUESTOS_DS; - ctxt->guestos_esp = virt_startinfo_addr; - - /* No debugging. */ - memset(ctxt->debugreg, 0, sizeof(ctxt->debugreg)); - - /* No callback handlers. */ - ctxt->event_callback_cs = FLAT_GUESTOS_CS; - ctxt->event_callback_eip = 0; - ctxt->failsafe_callback_cs = FLAT_GUESTOS_CS; - ctxt->failsafe_callback_eip = 0; - - memset( &launch_op, 0, sizeof(launch_op) ); - - launch_op.u.builddomain.domain = (domid_t)domid; - launch_op.u.builddomain.ctxt = ctxt; - launch_op.cmd = DOM0_BUILDDOMAIN; - rc = do_dom0_op(xc_handle, &launch_op); - - return rc; - - error_out: - if ( kernel_fd >= 0 ) - close(kernel_fd); - if( kernel_gfd ) - gzclose(kernel_gfd); - - return -1; -} - -#define MYSEEK_BUFSIZE 1024 -static off_t -myseek(gzFile gfd, off_t offset, int whence) -{ - unsigned char tmp[MYSEEK_BUFSIZE]; - int c; - - if ( offset < 0 ) - { - ERROR("seek back not supported"); - return -1; - } - - while ( offset != 0 ) - { - c = offset; - if ( c > MYSEEK_BUFSIZE ) - c = MYSEEK_BUFSIZE; - if ( gzread(gfd, tmp, c) != c ) - { - PERROR("Error seeking in image."); - return -1; - } - offset -= c; - } - - return 0; /* XXX */ -} - -/* - * NetBSD memory layout: - * - * ---------------- *virt_load_addr = ehdr.e_entry (0xc0100000) - * | kernel text | - * | | - * ---------------- - * | kernel data | - * | | - * ---------------- - * | kernel bss | - * | | - * ---------------- *symtab_addr - * | symtab size | = *symtab_len - * ---------------- - * | elf header | offsets to symbol sections mangled to be relative - * | | to headers location - * ---------------- - * | sym section | - * | headers | - * ---------------- - * | sym sections | - * | | - * ---------------- *symtab_addr + *symtab_len - * | padding | - * ---------------- ehdr.e_entry + *ksize << PAGE_SHIFT - */ - -#define IS_TEXT(p) (p.p_flags & PF_X) -#define IS_DATA(p) (p.p_flags & PF_W) -#define IS_BSS(p) (p.p_filesz < p.p_memsz) - -static int -loadelfimage(gzFile kernel_gfd, int pm_handle, unsigned long *page_array, - unsigned long tot_pages, unsigned long *virt_load_addr, - unsigned long *ksize, unsigned long *symtab_addr, - unsigned long *symtab_len) -{ - Elf_Ehdr ehdr; - Elf_Phdr *phdr; - Elf_Shdr *shdr; - void *vaddr; - char page[PAGE_SIZE], *p; - unsigned long iva, maxva, symva; - int c, curpos, h, i, ret, s; - - ret = -1; - phdr = NULL; - p = NULL; - maxva = 0; - - if ( gzread(kernel_gfd, &ehdr, sizeof(Elf_Ehdr)) != sizeof(Elf_Ehdr) ) - { - PERROR("Error reading kernel image ELF header."); - goto out; - } - curpos = sizeof(Elf_Ehdr); - - if ( !IS_ELF(ehdr) ) - { - PERROR("Image does not have an ELF header."); - goto out; - } - - *virt_load_addr = ehdr.e_entry; - - if ( (*virt_load_addr & (PAGE_SIZE-1)) != 0 ) - { - ERROR("We can only deal with page-aligned load addresses"); - goto out; - } - - if ( (*virt_load_addr + (tot_pages << PAGE_SHIFT)) > - HYPERVISOR_VIRT_START ) - { - ERROR("Cannot map all domain memory without hitting Xen space"); - goto out; - } - - - phdr = malloc(ehdr.e_phnum * sizeof(Elf_Phdr)); - if ( phdr == NULL ) - { - ERROR("Cannot allocate memory for Elf_Phdrs"); - goto out; - } - - if ( myseek(kernel_gfd, ehdr.e_phoff - curpos, SEEK_SET) == -1 ) - { - ERROR("Seek to program header failed"); - goto out; - } - curpos = ehdr.e_phoff; - - if ( gzread(kernel_gfd, phdr, ehdr.e_phnum * sizeof(Elf_Phdr)) != - ehdr.e_phnum * sizeof(Elf_Phdr) ) - { - PERROR("Error reading kernel image ELF program header."); - goto out; - } - curpos += ehdr.e_phnum * sizeof(Elf_Phdr); - - /* Copy run-time 'load' segments that are writeable and/or executable. */ - for ( h = 0; h < ehdr.e_phnum; h++ ) - { - if ( (phdr[h].p_type != PT_LOAD) || - ((phdr[h].p_flags & (PF_W|PF_X)) == 0) ) - continue; - - if ( IS_TEXT(phdr[h]) || IS_DATA(phdr[h]) ) - { - if ( myseek(kernel_gfd, phdr[h].p_offset - curpos, - SEEK_SET) == -1 ) - { - ERROR("Seek to section failed"); - goto out; - } - curpos = phdr[h].p_offset; - - for ( iva = phdr[h].p_vaddr; - iva < phdr[h].p_vaddr + phdr[h].p_filesz; - iva += c) - { - c = PAGE_SIZE - (iva & (PAGE_SIZE - 1)); - if (iva + c > phdr[h].p_vaddr + phdr[h].p_filesz) - c = phdr[h].p_vaddr + phdr[h].p_filesz - iva; - if ( gzread(kernel_gfd, page, c) != c ) - { - PERROR("Error reading kernel image page."); - goto out; - } - curpos += c; - vaddr = map_pfn_writeable(pm_handle, - page_array[(iva - *virt_load_addr) - >> PAGE_SHIFT]); - if ( vaddr == NULL ) - { - ERROR("Couldn't map guest memory"); - goto out; - } - DPRINTF(("copy page %p to %p, count 0x%x\n", (void *)iva, - vaddr + (iva & (PAGE_SIZE - 1)), c)); - memcpy(vaddr + (iva & (PAGE_SIZE - 1)), page, c); - unmap_pfn(pm_handle, vaddr); - } - - if ( phdr[h].p_vaddr + phdr[h].p_filesz > maxva ) - maxva = phdr[h].p_vaddr + phdr[h].p_filesz; - } - - if ( IS_BSS(phdr[h]) ) - { - /* XXX maybe clear phdr[h].p_memsz bytes from - phdr[h].p_vaddr + phdr[h].p_filesz ??? */ - if (phdr[h].p_vaddr + phdr[h].p_memsz > maxva) - maxva = phdr[h].p_vaddr + phdr[h].p_memsz; - DPRINTF(("bss from %p to %p, maxva %p\n", - (void *)(phdr[h].p_vaddr + phdr[h].p_filesz), - (void *)(phdr[h].p_vaddr + phdr[h].p_memsz), - (void *)maxva)); - } - } - - p = malloc(sizeof(int) + sizeof(Elf_Ehdr) + - ehdr.e_shnum * sizeof(Elf_Shdr)); - if ( p == NULL ) - { - ERROR("Cannot allocate memory for Elf_Shdrs"); - goto out; - } - - shdr = (Elf_Shdr *)(p + sizeof(int) + sizeof(Elf_Ehdr)); - - if ( myseek(kernel_gfd, ehdr.e_shoff - curpos, SEEK_SET) == -1 ) - { - ERROR("Seek to symbol header failed"); - goto out; - } - curpos = ehdr.e_shoff; - - if ( gzread(kernel_gfd, shdr, ehdr.e_shnum * sizeof(Elf_Shdr)) != - ehdr.e_shnum * sizeof(Elf_Shdr) ) - { - PERROR("Error reading kernel image ELF symbol header."); - goto out; - } - curpos += ehdr.e_shnum * sizeof(Elf_Shdr); - - maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1); - symva = maxva; - maxva += sizeof(int); - *symtab_addr = maxva; - *symtab_len = 0; - maxva += sizeof(Elf_Ehdr) + ehdr.e_shnum * sizeof(Elf_Shdr); - maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1); - - /* Copy kernel string / symbol tables into physical memory */ - for ( h = 0; h < ehdr.e_shnum; h++ ) - { - if ( shdr[h].sh_type == SHT_STRTAB ) - { - /* Look for a strtab @i linked to symtab @h. */ - for ( i = 0; i < ehdr.e_shnum; i++ ) - if ( (shdr[i].sh_type == SHT_SYMTAB) && - (shdr[i].sh_link == h) ) - break; - /* Skip symtab @h if we found no corresponding strtab @i. */ - if ( i == ehdr.e_shnum ) - { - shdr[h].sh_offset = 0; - continue; - } - } - - if ( (shdr[h].sh_type == SHT_STRTAB) || - (shdr[h].sh_type == SHT_SYMTAB) ) - { - if ( myseek(kernel_gfd, shdr[h].sh_offset - curpos, - SEEK_SET) == -1 ) - { - ERROR("Seek to symbol section failed"); - goto out; - } - curpos = shdr[h].sh_offset; - - /* Mangled to be based on ELF header location. */ - shdr[h].sh_offset = maxva - *symtab_addr; - - DPRINTF(("copy section %d, size 0x%x\n", h, shdr[h].sh_size)); - for ( i = 0; i < shdr[h].sh_size; i += c, maxva += c ) - { - c = PAGE_SIZE - (maxva & (PAGE_SIZE - 1)); - if ( c > (shdr[h].sh_size - i) ) - c = shdr[h].sh_size - i; - if ( gzread(kernel_gfd, page, c) != c ) - { - PERROR("Error reading kernel image page."); - goto out; - } - curpos += c; - - vaddr = map_pfn_writeable(pm_handle, - page_array[(maxva - *virt_load_addr) - >> PAGE_SHIFT]); - if ( vaddr == NULL ) - { - ERROR("Couldn't map guest memory"); - goto out; - } - DPRINTF(("copy page %p to %p, count 0x%x\n", (void *)maxva, - vaddr + (maxva & (PAGE_SIZE - 1)), c)); - memcpy(vaddr + (maxva & (PAGE_SIZE - 1)), page, c); - unmap_pfn(pm_handle, vaddr); - } - - *symtab_len += shdr[h].sh_size; - maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1); - - } - shdr[h].sh_name = 0; /* Name is NULL. */ - } - - if ( *symtab_len == 0 ) - { - DPRINTF(("no symbol table\n")); - *symtab_addr = 0; - ret = 0; - goto out; - } - - DPRINTF(("sym header va %p from %p/%p size %x/%x\n", (void *)symva, - shdr, p, ehdr.e_shnum * sizeof(Elf_Shdr), - ehdr.e_shnum * sizeof(Elf_Shdr) + sizeof(Elf_Ehdr))); - ehdr.e_phoff = 0; - ehdr.e_shoff = sizeof(Elf_Ehdr); - ehdr.e_phentsize = 0; - ehdr.e_phnum = 0; - ehdr.e_shstrndx = SHN_UNDEF; - memcpy(p + sizeof(int), &ehdr, sizeof(Elf_Ehdr)); - *(int *)p = maxva - *symtab_addr; - - /* Copy total length, crafted ELF header and section header table */ - s = sizeof(int) + sizeof(Elf_Ehdr) + ehdr.e_shnum * sizeof(Elf_Shdr); - for ( i = 0; i < s; i += c, symva += c ) - { - c = PAGE_SIZE - (symva & (PAGE_SIZE - 1)); - if ( c > s - i ) - c = s - i; - vaddr = map_pfn_writeable(pm_handle, - page_array[(symva - *virt_load_addr) - >> PAGE_SHIFT]); - if ( vaddr == NULL ) - { - ERROR("Couldn't map guest memory"); - goto out; - } - DPRINTF(("copy page %p to %p, count 0x%x\n", (void *)symva, - vaddr + (symva & (PAGE_SIZE - 1)), c)); - memcpy(vaddr + (symva & (PAGE_SIZE - 1)), p + i, - c); - unmap_pfn(pm_handle, vaddr); - } - - *symtab_len = maxva - *symtab_addr; - - ret = 0; - - out: - if ( ret == 0 ) - { - maxva = (maxva + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); - *ksize = (maxva - *virt_load_addr) >> PAGE_SHIFT; - - DPRINTF(("virt_addr %p, kpages 0x%lx, symtab_addr %p, symtab_len %p\n", - (void *)*virt_load_addr, *ksize, (void *)*symtab_addr, - (void *)*symtab_len)); - } - - if ( phdr != NULL ) - free(phdr); - if ( p != NULL ) - free(p); - return ret; -} diff --git a/tools/xc/lib/xc_physdev.c b/tools/xc/lib/xc_physdev.c deleted file mode 100644 index ba5dd9ccdc..0000000000 --- a/tools/xc/lib/xc_physdev.c +++ /dev/null @@ -1,29 +0,0 @@ -/****************************************************************************** - * xc_physdev.c - * - * API for manipulating physical-device access permissions. - * - * Copyright (c) 2004, Rolf Neugebauer (Intel Research Cambridge) - * Copyright (c) 2004, K A Fraser (University of Cambridge) - */ - -#include "xc_private.h" - -int xc_physdev_pci_access_modify(int xc_handle, - u32 domid, - int bus, - int dev, - int func, - int enable) -{ - dom0_op_t op; - - op.cmd = DOM0_PCIDEV_ACCESS; - op.u.pcidev_access.domain = (domid_t)domid; - op.u.pcidev_access.bus = bus; - op.u.pcidev_access.dev = dev; - op.u.pcidev_access.func = func; - op.u.pcidev_access.enable = enable; - - return do_dom0_op(xc_handle, &op); -} diff --git a/tools/xc/lib/xc_private.c b/tools/xc/lib/xc_private.c deleted file mode 100644 index 344f48254d..0000000000 --- a/tools/xc/lib/xc_private.c +++ /dev/null @@ -1,230 +0,0 @@ -/****************************************************************************** - * xc_private.c - * - * Helper functions for the rest of the library. - */ - -#include "xc_private.h" - -int init_pfn_mapper(domid_t domid) -{ - int fd = open("/dev/mem", O_RDWR); - if ( fd >= 0 ) - (void)ioctl(fd, _IO('M', 1), (unsigned long)domid); - return fd; -} - -int close_pfn_mapper(int pm_handle) -{ - return close(pm_handle); -} - -void *map_pfn_writeable(int pm_handle, unsigned long pfn) -{ - void *vaddr = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE, - MAP_SHARED, pm_handle, pfn << PAGE_SHIFT); - if ( vaddr == MAP_FAILED ) - return NULL; - return vaddr; -} - -void *map_pfn_readonly(int pm_handle, unsigned long pfn) -{ - void *vaddr = mmap(NULL, PAGE_SIZE, PROT_READ, - MAP_SHARED, pm_handle, pfn << PAGE_SHIFT); - if ( vaddr == MAP_FAILED ) - return NULL; - return vaddr; -} - -void unmap_pfn(int pm_handle, void *vaddr) -{ - (void)munmap(vaddr, PAGE_SIZE); -} - -/*******************/ - -void * mfn_mapper_map_batch(int xc_handle, domid_t dom, int prot, - unsigned long *arr, int num ) -{ - privcmd_mmapbatch_t ioctlx; - void *addr; - addr = mmap( NULL, num*PAGE_SIZE, prot, MAP_SHARED, xc_handle, 0 ); - if (addr) - { - ioctlx.num=num; - ioctlx.dom=dom; - ioctlx.addr=(unsigned long)addr; - ioctlx.arr=arr; - if ( ioctl( xc_handle, IOCTL_PRIVCMD_MMAPBATCH, &ioctlx ) < 0 ) - { - perror("XXXXXXXX"); - munmap(addr, num*PAGE_SIZE); - return 0; - } - } - return addr; - -} - -/*******************/ - -void * mfn_mapper_map_single(int xc_handle, domid_t dom, - int size, int prot, - unsigned long mfn ) -{ - privcmd_mmap_t ioctlx; - privcmd_mmap_entry_t entry; - void *addr; - addr = mmap( NULL, size, prot, MAP_SHARED, xc_handle, 0 ); - if (addr) - { - ioctlx.num=1; - ioctlx.dom=dom; - ioctlx.entry=&entry; - entry.va=(unsigned long) addr; - entry.mfn=mfn; - entry.npages=(size+PAGE_SIZE-1)>>PAGE_SHIFT; - if ( ioctl( xc_handle, IOCTL_PRIVCMD_MMAP, &ioctlx ) <0 ) - { - munmap(addr, size); - return 0; - } - } - return addr; -} - -/*******************/ - -/* NB: arr must be mlock'ed */ -int get_pfn_type_batch(int xc_handle, - u32 dom, int num, unsigned long *arr) -{ - dom0_op_t op; - op.cmd = DOM0_GETPAGEFRAMEINFO2; - op.u.getpageframeinfo2.domain = (domid_t)dom; - op.u.getpageframeinfo2.num = num; - op.u.getpageframeinfo2.array = arr; - return do_dom0_op(xc_handle, &op); -} - -#define GETPFN_ERR (~0U) -unsigned int get_pfn_type(int xc_handle, - unsigned long mfn, - u32 dom) -{ - dom0_op_t op; - op.cmd = DOM0_GETPAGEFRAMEINFO; - op.u.getpageframeinfo.pfn = mfn; - op.u.getpageframeinfo.domain = (domid_t)dom; - if ( do_dom0_op(xc_handle, &op) < 0 ) - { - PERROR("Unexpected failure when getting page frame info!"); - return GETPFN_ERR; - } - return op.u.getpageframeinfo.type; -} - - - -/*******************/ - -#define FIRST_MMU_UPDATE 1 - -static int flush_mmu_updates(int xc_handle, mmu_t *mmu) -{ - int err = 0; - privcmd_hypercall_t hypercall; - - if ( mmu->idx == FIRST_MMU_UPDATE ) - return 0; - - /* The first two requests set the correct subject domain (PTS and GPS). */ - mmu->updates[0].val = (unsigned long)(mmu->subject<<16) & ~0xFFFFUL; - mmu->updates[0].ptr = (unsigned long)(mmu->subject<< 0) & ~0xFFFFUL; - mmu->updates[0].ptr |= MMU_EXTENDED_COMMAND; - mmu->updates[0].val |= MMUEXT_SET_SUBJECTDOM | SET_PAGETABLE_SUBJECTDOM; - - hypercall.op = __HYPERVISOR_mmu_update; - hypercall.arg[0] = (unsigned long)mmu->updates; - hypercall.arg[1] = (unsigned long)mmu->idx; - hypercall.arg[2] = 0; - - if ( mlock(mmu->updates, sizeof(mmu->updates)) != 0 ) - { - PERROR("Could not lock pagetable update array"); - err = 1; - goto out; - } - - if ( do_xen_hypercall(xc_handle, &hypercall) < 0 ) - { - ERROR("Failure when submitting mmu updates"); - err = 1; - } - - mmu->idx = FIRST_MMU_UPDATE; - - (void)munlock(mmu->updates, sizeof(mmu->updates)); - - out: - return err; -} - -mmu_t *init_mmu_updates(int xc_handle, domid_t dom) -{ - mmu_t *mmu = malloc(sizeof(mmu_t)); - if ( mmu == NULL ) - return mmu; - mmu->idx = FIRST_MMU_UPDATE; - mmu->subject = dom; - return mmu; -} - -int add_mmu_update(int xc_handle, mmu_t *mmu, - unsigned long ptr, unsigned long val) -{ - mmu->updates[mmu->idx].ptr = ptr; - mmu->updates[mmu->idx].val = val; - - if ( ++mmu->idx == MAX_MMU_UPDATES ) - return flush_mmu_updates(xc_handle, mmu); - - return 0; -} - -int finish_mmu_updates(int xc_handle, mmu_t *mmu) -{ - return flush_mmu_updates(xc_handle, mmu); -} - - -long long xc_domain_get_cpu_usage( int xc_handle, domid_t domid ) -{ - dom0_op_t op; - - op.cmd = DOM0_GETDOMAININFO; - op.u.getdomaininfo.domain = (domid_t)domid; - op.u.getdomaininfo.ctxt = NULL; - if ( (do_dom0_op(xc_handle, &op) < 0) || - ((u32)op.u.getdomaininfo.domain != domid) ) - { - PERROR("Could not get info on domain"); - return -1; - } - return op.u.getdomaininfo.cpu_time; -} - - -/* This is shared between save and restore, and may generally be useful. */ -unsigned long csum_page (void * page) -{ - int i; - unsigned long *p = page; - unsigned long long sum=0; - - for ( i = 0; i < (PAGE_SIZE/sizeof(unsigned long)); i++ ) - sum += p[i]; - - return sum ^ (sum>>32); -} diff --git a/tools/xc/lib/xc_private.h b/tools/xc/lib/xc_private.h deleted file mode 100644 index 742185161b..0000000000 --- a/tools/xc/lib/xc_private.h +++ /dev/null @@ -1,213 +0,0 @@ - -#ifndef __XC_PRIVATE_H__ -#define __XC_PRIVATE_H__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "xc.h" - -/* from xen/include/hypervisor-ifs */ -#include -#include -#include -#include - -#include - -/* from xend/lib */ -#include - -#define _PAGE_PRESENT 0x001 -#define _PAGE_RW 0x002 -#define _PAGE_USER 0x004 -#define _PAGE_PWT 0x008 -#define _PAGE_PCD 0x010 -#define _PAGE_ACCESSED 0x020 -#define _PAGE_DIRTY 0x040 -#define _PAGE_PAT 0x080 -#define _PAGE_PSE 0x080 -#define _PAGE_GLOBAL 0x100 - - -#define L1_PAGETABLE_SHIFT 12 -#define L2_PAGETABLE_SHIFT 22 - -#define ENTRIES_PER_L1_PAGETABLE 1024 -#define ENTRIES_PER_L2_PAGETABLE 1024 - -#define PAGE_SHIFT L1_PAGETABLE_SHIFT -#define PAGE_SIZE (1UL << PAGE_SHIFT) -#define PAGE_MASK (~(PAGE_SIZE-1)) - -typedef unsigned long l1_pgentry_t; -typedef unsigned long l2_pgentry_t; - -#define l1_table_offset(_a) \ - (((_a) >> L1_PAGETABLE_SHIFT) & (ENTRIES_PER_L1_PAGETABLE - 1)) -#define l2_table_offset(_a) \ - ((_a) >> L2_PAGETABLE_SHIFT) - -#define ERROR(_m, _a...) \ - fprintf(stderr, "ERROR: " _m "\n" , ## _a ) - -#define PERROR(_m, _a...) \ - fprintf(stderr, "ERROR: " _m " (%d = %s)\n" , ## _a , \ - errno, strerror(errno)) - -static inline int do_privcmd(int xc_handle, - unsigned int cmd, - unsigned long data) -{ - return ioctl(xc_handle, cmd, data); -} - -static inline int do_xen_hypercall(int xc_handle, - privcmd_hypercall_t *hypercall) -{ - return do_privcmd(xc_handle, - IOCTL_PRIVCMD_HYPERCALL, - (unsigned long)hypercall); -} - -static inline int do_dom0_op(int xc_handle, dom0_op_t *op) -{ - int ret = -1; - privcmd_hypercall_t hypercall; - - op->interface_version = DOM0_INTERFACE_VERSION; - - hypercall.op = __HYPERVISOR_dom0_op; - hypercall.arg[0] = (unsigned long)op; - - if ( mlock(op, sizeof(*op)) != 0 ) - { - PERROR("Could not lock memory for Xen hypercall"); - goto out1; - } - - if ( (ret = do_xen_hypercall(xc_handle, &hypercall)) < 0 ) - { - if ( errno == EACCES ) - fprintf(stderr, "Dom0 operation failed -- need to" - " rebuild the user-space tool set?\n"); - goto out2; - } - - out2: (void)munlock(op, sizeof(*op)); - out1: return ret; -} - -static inline int do_multicall_op(int xc_handle, - void *call_list, int nr_calls) -{ - int ret = -1; - privcmd_hypercall_t hypercall; - - hypercall.op = __HYPERVISOR_multicall; - hypercall.arg[0] = (unsigned long)call_list; - hypercall.arg[1] = (unsigned long)nr_calls; - - if ( (ret = do_xen_hypercall(xc_handle, &hypercall)) < 0 ) - { - if ( errno == EACCES ) - fprintf(stderr, "Dom0 operation failed -- need to" - " rebuild the user-space tool set?\n"); - goto out1; - } - - out1: return ret; -} - -/* - * PFN mapping. - */ -int init_pfn_mapper(domid_t domid); -int close_pfn_mapper(int pm_handle); -void *map_pfn_writeable(int pm_handle, unsigned long pfn); -void *map_pfn_readonly(int pm_handle, unsigned long pfn); -void unmap_pfn(int pm_handle, void *vaddr); -int get_pfn_type_batch(int xc_handle, u32 dom, int num, unsigned long *arr); -unsigned long csum_page (void * page); - -/* - * MMU updates. - */ -#define MAX_MMU_UPDATES 1024 -typedef struct { - mmu_update_t updates[MAX_MMU_UPDATES]; - int idx; - domid_t subject; -} mmu_t; -mmu_t *init_mmu_updates(int xc_handle, domid_t dom); -int add_mmu_update(int xc_handle, mmu_t *mmu, - unsigned long ptr, unsigned long val); -int finish_mmu_updates(int xc_handle, mmu_t *mmu); - - -/* - * ioctl-based mfn mapping interface - */ - -/* -typedef struct privcmd_mmap_entry { - unsigned long va; - unsigned long mfn; - unsigned long npages; -} privcmd_mmap_entry_t; - -typedef struct privcmd_mmap { - int num; - domid_t dom; - privcmd_mmap_entry_t *entry; -} privcmd_mmap_t; -*/ - -#define mfn_mapper_queue_size 128 - -typedef struct mfn_mapper { - int xc_handle; - int size; - int prot; - int error; - int max_queue_size; - void * addr; - privcmd_mmap_t ioctl; - -} mfn_mapper_t; - -void * mfn_mapper_map_single(int xc_handle, domid_t dom, int size, int prot, - unsigned long mfn ); - -void * mfn_mapper_map_batch(int xc_handle, domid_t dom, int prot, - unsigned long *arr, int num ); - -mfn_mapper_t * mfn_mapper_init(int xc_handle, domid_t dom, int size, int prot); - -void * mfn_mapper_base(mfn_mapper_t *t); - -void mfn_mapper_close(mfn_mapper_t *t); - -int mfn_mapper_flush_queue(mfn_mapper_t *t); - -void * mfn_mapper_queue_entry(mfn_mapper_t *t, int offset, - unsigned long mfn, int size ); - -long long xc_domain_get_cpu_usage( int xc_handle, domid_t domid ); - -#include "xc_io.h" - -int xc_domain_getfullinfo(int xc_handle, - u32 domid, - dom0_op_t *op, - full_execution_context_t *ctxt ); -#endif /* __XC_PRIVATE_H__ */ diff --git a/tools/xc/lib/xc_rrobin.c b/tools/xc/lib/xc_rrobin.c deleted file mode 100644 index ad37962f3b..0000000000 --- a/tools/xc/lib/xc_rrobin.c +++ /dev/null @@ -1,37 +0,0 @@ -/****************************************************************************** - * xc_rrobin.c - * - * API for manipulating parameters of the Round Robin scheduler - * - * by Mark Williamson, Copyright (c) 2004 Intel Research Cambridge. - */ - -#include "xc_private.h" - -int xc_rrobin_global_set(int xc_handle, u64 slice) -{ - dom0_op_t op; - op.cmd = DOM0_SCHEDCTL; - op.u.schedctl.sched_id = SCHED_RROBIN; - op.u.schedctl.direction = SCHED_INFO_PUT; - - op.u.schedctl.u.rrobin.slice = slice; - return do_dom0_op(xc_handle, &op); -} - - -int xc_rrobin_global_get(int xc_handle, u64 *slice) -{ - dom0_op_t op; - int ret; - - op.cmd = DOM0_SCHEDCTL; - op.u.schedctl.sched_id = SCHED_RROBIN; - op.u.schedctl.direction = SCHED_INFO_GET; - - ret = do_dom0_op(xc_handle, &op); - - *slice = op.u.schedctl.u.rrobin.slice; - - return ret; -} diff --git a/tools/xc/py/Makefile b/tools/xc/py/Makefile deleted file mode 100644 index 7dc74a1072..0000000000 --- a/tools/xc/py/Makefile +++ /dev/null @@ -1,15 +0,0 @@ - -all: - python setup.py build - -install: all - if [ "$(prefix)" = "" ]; then \ - python setup.py install; \ - elif [ "$(dist)" = "yes" ]; then \ - python setup.py install --home="$(prefix)"; \ - else \ - python setup.py install --root="$(prefix)"; \ - fi - -clean: - rm -rf build *.pyc *.pyo *.o *.a *~ diff --git a/tools/xc/py/Xc.c b/tools/xc/py/Xc.c deleted file mode 100644 index 2eb70cf2a0..0000000000 --- a/tools/xc/py/Xc.c +++ /dev/null @@ -1,1160 +0,0 @@ -/****************************************************************************** - * Xc.c - * - * Copyright (c) 2003-2004, K A Fraser (University of Cambridge) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "xc_private.h" -#include "gzip_stream.h" - -/* Needed for Python versions earlier than 2.3. */ -#ifndef PyMODINIT_FUNC -#define PyMODINIT_FUNC DL_EXPORT(void) -#endif - -#define XENPKG "xen.ext.xc" - -static PyObject *xc_error, *zero; - -typedef struct { - PyObject_HEAD; - int xc_handle; -} XcObject; - -/* - * Definitions for the 'xc' object type. - */ - -static PyObject *pyxc_domain_create(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - unsigned int mem_kb = 0; - char *name = "(anon)"; - int cpu = -1; - u32 dom; - int ret; - - static char *kwd_list[] = { "mem_kb", "name", "cpu", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|isi", kwd_list, - &mem_kb, &name, &cpu) ) - return NULL; - - if ( (ret = xc_domain_create(xc->xc_handle, mem_kb, name, cpu, &dom)) < 0 ) - return PyErr_SetFromErrno(xc_error); - - return PyInt_FromLong(dom); -} - -static PyObject *pyxc_domain_pause(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - u32 dom; - - static char *kwd_list[] = { "dom", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &dom) ) - return NULL; - - if ( xc_domain_pause(xc->xc_handle, dom) != 0 ) - return PyErr_SetFromErrno(xc_error); - - Py_INCREF(zero); - return zero; -} - -static PyObject *pyxc_domain_unpause(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - u32 dom; - - static char *kwd_list[] = { "dom", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &dom) ) - return NULL; - - if ( xc_domain_unpause(xc->xc_handle, dom) != 0 ) - return PyErr_SetFromErrno(xc_error); - - Py_INCREF(zero); - return zero; -} - -static PyObject *pyxc_domain_destroy(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - u32 dom; - - static char *kwd_list[] = { "dom", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &dom) ) - return NULL; - - if ( xc_domain_destroy(xc->xc_handle, dom) != 0 ) - return PyErr_SetFromErrno(xc_error); - - Py_INCREF(zero); - return zero; -} - -static PyObject *pyxc_domain_pincpu(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - u32 dom; - int cpu = -1; - - static char *kwd_list[] = { "dom", "cpu", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list, - &dom, &cpu) ) - return NULL; - - if ( xc_domain_pincpu(xc->xc_handle, dom, cpu) != 0 ) - return PyErr_SetFromErrno(xc_error); - - Py_INCREF(zero); - return zero; -} - -static PyObject *pyxc_domain_getinfo(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - PyObject *list; - - u32 first_dom = 0; - int max_doms = 1024, nr_doms, i; - xc_dominfo_t *info; - - static char *kwd_list[] = { "first_dom", "max_doms", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwd_list, - &first_dom, &max_doms) ) - return NULL; - - if ( (info = malloc(max_doms * sizeof(xc_dominfo_t))) == NULL ) - return PyErr_NoMemory(); - - nr_doms = xc_domain_getinfo(xc->xc_handle, first_dom, max_doms, info); - - list = PyList_New(nr_doms); - for ( i = 0 ; i < nr_doms; i++ ) - { - PyList_SetItem( - list, i, - Py_BuildValue("{s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i" - ",s:l,s:L,s:s,s:l,s:i}", - "dom", info[i].domid, - "cpu", info[i].cpu, - "dying", info[i].dying, - "crashed", info[i].crashed, - "shutdown", info[i].shutdown, - "paused", info[i].paused, - "blocked", info[i].blocked, - "running", info[i].running, - "mem_kb", info[i].nr_pages*4, - "cpu_time", info[i].cpu_time, - "name", info[i].name, - "maxmem_kb", info[i].max_memkb, - "shutdown_reason", info[i].shutdown_reason - )); - } - - free(info); - - return list; -} - -static int file_save(XcObject *xc, XcIOContext *ctxt, char *state_file){ - int rc = -1; - int fd = -1; - int open_flags = (O_CREAT | O_EXCL | O_WRONLY); - int open_mode = 0644; - - printf("%s>\n", __FUNCTION__); - fd = open(state_file, open_flags, open_mode); - if(fd < 0){ - xcio_perror(ctxt, "Could not open file for writing"); - goto exit; - } - /* Compression rate 1: we want speed over compression. - * We're mainly going for those zero pages, after all. - */ - printf("%s>gzip_stream_fdopen... \n", __FUNCTION__); - ctxt->io = gzip_stream_fdopen(fd, "wb1"); - if(!ctxt->io){ - xcio_perror(ctxt, "Could not allocate compression state"); - goto exit; - } - printf("%s> xc_linux_save...\n", __FUNCTION__); - rc = xc_linux_save(xc->xc_handle, ctxt); - exit: - if(ctxt->io) IOStream_close(ctxt->io); - if(fd >= 0) close(fd); - unlink(state_file); - printf("%s> rc=%d\n", __FUNCTION__, rc); - return rc; -} - -static PyObject *pyxc_linux_save(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - u32 dom; - char *state_file; - int progress = 1, debug = 0; - unsigned int flags = 0; - PyObject *val = NULL; - int rc = -1; - XcIOContext ioctxt = { .info = iostdout, .err = iostderr }; - - static char *kwd_list[] = { "dom", "state_file", "vmconfig", "progress", "debug", NULL }; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "is|sii", kwd_list, - &ioctxt.domain, - &state_file, - &ioctxt.vmconfig, - &progress, - &debug)){ - goto exit; - } - ioctxt.vmconfig_n = (ioctxt.vmconfig ? strlen(ioctxt.vmconfig) : 0); - if (progress) ioctxt.flags |= XCFLAGS_VERBOSE; - if (debug) ioctxt.flags |= XCFLAGS_DEBUG; - if(!state_file || state_file[0] == '\0') goto exit; - rc = file_save(xc, &ioctxt, state_file); - if(rc){ - PyErr_SetFromErrno(xc_error); - goto exit; - } - //xc_domain_destroy(xc->xc_handle, dom); - Py_INCREF(zero); - val = zero; - exit: - return val; -} - - -static int file_restore(XcObject *xc, XcIOContext *ioctxt, char *state_file){ - int rc = -1; - - ioctxt->io = gzip_stream_fopen(state_file, "rb"); - if (!ioctxt->io) { - xcio_perror(ioctxt, "Could not open file for reading"); - goto exit; - } - - rc = xc_linux_restore(xc->xc_handle, ioctxt); - exit: - if(ioctxt->io) IOStream_close(ioctxt->io); - return rc; -} - -static PyObject *pyxc_linux_restore(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - char *state_file; - int progress = 1, debug = 0; - u32 dom; - PyObject *val = NULL; - XcIOContext ioctxt = { .info = iostdout, .err = iostderr }; - int rc =-1; - - static char *kwd_list[] = { "state_file", "progress", "debug", NULL }; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "is|ii", kwd_list, - &ioctxt.domain, - &state_file, - &progress, - &debug)){ - goto exit; - } - if (progress) ioctxt.flags |= XCFLAGS_VERBOSE; - if (debug) ioctxt.flags |= XCFLAGS_DEBUG; - - if(!state_file || state_file[0] == '\0') goto exit; - rc = file_restore(xc, &ioctxt, state_file); - if(rc){ - PyErr_SetFromErrno(xc_error); - goto exit; - } - val = Py_BuildValue("{s:i,s:s}", - "dom", ioctxt.domain, - "vmconfig", ioctxt.vmconfig); - //? free(ioctxt.vmconfig); - exit: - return val; -} - -static PyObject *pyxc_linux_build(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - u32 dom; - char *image, *ramdisk = NULL, *cmdline = ""; - int control_evtchn, flags = 0; - - static char *kwd_list[] = { "dom", "control_evtchn", - "image", "ramdisk", "cmdline", "flags", - NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iis|ssi", kwd_list, - &dom, &control_evtchn, - &image, &ramdisk, &cmdline, &flags) ) - return NULL; - - if ( xc_linux_build(xc->xc_handle, dom, image, - ramdisk, cmdline, control_evtchn, flags) != 0 ) - return PyErr_SetFromErrno(xc_error); - - Py_INCREF(zero); - return zero; -} - -static PyObject *pyxc_netbsd_build(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - u32 dom; - char *image, *ramdisk = NULL, *cmdline = ""; - int control_evtchn; - - static char *kwd_list[] = { "dom", "control_evtchn", - "image", "ramdisk", "cmdline", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iis|ssi", kwd_list, - &dom, &control_evtchn, - &image, &ramdisk, &cmdline) ) - return NULL; - - if ( xc_netbsd_build(xc->xc_handle, dom, image, - cmdline, control_evtchn) != 0 ) - return PyErr_SetFromErrno(xc_error); - - Py_INCREF(zero); - return zero; -} - -static PyObject *pyxc_bvtsched_global_set(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - unsigned long ctx_allow; - - static char *kwd_list[] = { "ctx_allow", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "l", kwd_list, &ctx_allow) ) - return NULL; - - if ( xc_bvtsched_global_set(xc->xc_handle, ctx_allow) != 0 ) - return PyErr_SetFromErrno(xc_error); - - Py_INCREF(zero); - return zero; -} - -static PyObject *pyxc_bvtsched_global_get(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - unsigned long ctx_allow; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - if ( xc_bvtsched_global_get(xc->xc_handle, &ctx_allow) != 0 ) - return PyErr_SetFromErrno(xc_error); - - return Py_BuildValue("s:l", "ctx_allow", ctx_allow); -} - -static PyObject *pyxc_bvtsched_domain_set(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - u32 dom; - unsigned long mcuadv, warp, warpl, warpu; - - static char *kwd_list[] = { "dom", "mcuadv", "warp", "warpl", - "warpu", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "illll", kwd_list, - &dom, &mcuadv, &warp, &warpl, &warpu) ) - return NULL; - - if ( xc_bvtsched_domain_set(xc->xc_handle, dom, mcuadv, - warp, warpl, warpu) != 0 ) - return PyErr_SetFromErrno(xc_error); - - Py_INCREF(zero); - return zero; -} - -static PyObject *pyxc_bvtsched_domain_get(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - u32 dom; - unsigned long mcuadv, warp, warpl, warpu; - - static char *kwd_list[] = { "dom", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &dom) ) - return NULL; - - if ( xc_bvtsched_domain_get(xc->xc_handle, dom, &mcuadv, &warp, - &warpl, &warpu) != 0 ) - return PyErr_SetFromErrno(xc_error); - - return Py_BuildValue("{s:i,s:l,s:l,s:l,s:l}", - "domain", dom, - "mcuadv", mcuadv, - "warp", warp, - "warpl", warpl, - "warpu", warpu); -} - -static PyObject *pyxc_evtchn_bind_interdomain(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - u32 dom1 = DOMID_SELF, dom2 = DOMID_SELF; - int port1, port2; - - static char *kwd_list[] = { "dom1", "dom2", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwd_list, - &dom1, &dom2) ) - return NULL; - - if ( xc_evtchn_bind_interdomain(xc->xc_handle, dom1, - dom2, &port1, &port2) != 0 ) - return PyErr_SetFromErrno(xc_error); - - return Py_BuildValue("{s:i,s:i}", - "port1", port1, - "port2", port2); -} - -static PyObject *pyxc_evtchn_bind_virq(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - int virq, port; - - static char *kwd_list[] = { "virq", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &virq) ) - return NULL; - - if ( xc_evtchn_bind_virq(xc->xc_handle, virq, &port) != 0 ) - return PyErr_SetFromErrno(xc_error); - - return PyInt_FromLong(port); -} - -static PyObject *pyxc_evtchn_close(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - u32 dom = DOMID_SELF; - int port; - - static char *kwd_list[] = { "port", "dom", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list, - &port, &dom) ) - return NULL; - - if ( xc_evtchn_close(xc->xc_handle, dom, port) != 0 ) - return PyErr_SetFromErrno(xc_error); - - Py_INCREF(zero); - return zero; -} - -static PyObject *pyxc_evtchn_send(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - int port; - - static char *kwd_list[] = { "port", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &port) ) - return NULL; - - if ( xc_evtchn_send(xc->xc_handle, port) != 0 ) - return PyErr_SetFromErrno(xc_error); - - Py_INCREF(zero); - return zero; -} - -static PyObject *pyxc_evtchn_status(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - PyObject *dict; - - u32 dom = DOMID_SELF; - int port, ret; - xc_evtchn_status_t status; - - static char *kwd_list[] = { "port", "dom", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list, - &port, &dom) ) - return NULL; - - ret = xc_evtchn_status(xc->xc_handle, dom, port, &status); - if ( ret != 0 ) - return PyErr_SetFromErrno(xc_error); - - switch ( status.status ) - { - case EVTCHNSTAT_closed: - dict = Py_BuildValue("{s:s}", - "status", "closed"); - break; - case EVTCHNSTAT_unbound: - dict = Py_BuildValue("{s:s}", - "status", "unbound"); - break; - case EVTCHNSTAT_interdomain: - dict = Py_BuildValue("{s:s,s:i,s:i}", - "status", "interdomain", - "dom", status.u.interdomain.dom, - "port", status.u.interdomain.port); - break; - case EVTCHNSTAT_pirq: - dict = Py_BuildValue("{s:s,s:i}", - "status", "pirq", - "irq", status.u.pirq); - break; - case EVTCHNSTAT_virq: - dict = Py_BuildValue("{s:s,s:i}", - "status", "virq", - "irq", status.u.virq); - break; - default: - dict = Py_BuildValue("{}"); - break; - } - - return dict; -} - -static PyObject *pyxc_physdev_pci_access_modify(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - u32 dom; - int bus, dev, func, enable, ret; - - static char *kwd_list[] = { "dom", "bus", "dev", "func", "enable", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiiii", kwd_list, - &dom, &bus, &dev, &func, &enable) ) - return NULL; - - ret = xc_physdev_pci_access_modify( - xc->xc_handle, dom, bus, dev, func, enable); - if ( ret != 0 ) - return PyErr_SetFromErrno(xc_error); - - Py_INCREF(zero); - return zero; -} - -static PyObject *pyxc_readconsolering(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - unsigned int clear = 0; - char str[32768]; - int ret; - - static char *kwd_list[] = { "clear", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwd_list, &clear) ) - return NULL; - - ret = xc_readconsolering(xc->xc_handle, str, sizeof(str), clear); - if ( ret < 0 ) - return PyErr_SetFromErrno(xc_error); - - return PyString_FromStringAndSize(str, ret); -} - -static PyObject *pyxc_physinfo(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - xc_physinfo_t info; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - if ( xc_physinfo(xc->xc_handle, &info) != 0 ) - return PyErr_SetFromErrno(xc_error); - - return Py_BuildValue("{s:i,s:i,s:l,s:l,s:l}", - "ht_per_core", info.ht_per_core, - "cores", info.cores, - "total_pages", info.total_pages, - "free_pages", info.free_pages, - "cpu_khz", info.cpu_khz); -} - -static PyObject *pyxc_atropos_domain_set(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - u32 domid; - u64 period, slice, latency; - int xtratime; - - static char *kwd_list[] = { "dom", "period", "slice", "latency", - "xtratime", NULL }; - - if( !PyArg_ParseTupleAndKeywords(args, kwds, "iLLLi", kwd_list, &domid, - &period, &slice, &latency, &xtratime) ) - return NULL; - - if ( xc_atropos_domain_set(xc->xc_handle, domid, period, slice, - latency, xtratime) != 0 ) - return PyErr_SetFromErrno(xc_error); - - Py_INCREF(zero); - return zero; -} - -static PyObject *pyxc_atropos_domain_get(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - u32 domid; - u64 period, slice, latency; - int xtratime; - - static char *kwd_list[] = { "dom", NULL }; - - if( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &domid) ) - return NULL; - - if ( xc_atropos_domain_get( xc->xc_handle, domid, &period, - &slice, &latency, &xtratime ) ) - return PyErr_SetFromErrno(xc_error); - - return Py_BuildValue("{s:i,s:L,s:L,s:L,s:i}", - "domain", domid, - "period", period, - "slice", slice, - "latency", latency, - "xtratime", xtratime); -} - - -static PyObject *pyxc_rrobin_global_set(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - u64 slice; - - static char *kwd_list[] = { "slice", NULL }; - - if( !PyArg_ParseTupleAndKeywords(args, kwds, "L", kwd_list, &slice) ) - return NULL; - - if ( xc_rrobin_global_set(xc->xc_handle, slice) != 0 ) - return PyErr_SetFromErrno(xc_error); - - Py_INCREF(zero); - return zero; -} - -static PyObject *pyxc_shadow_control(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - u32 dom; - int op=0; - - static char *kwd_list[] = { "dom", "op", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list, - &dom, &op) ) - return NULL; - - if ( xc_shadow_control(xc->xc_handle, dom, op, NULL, 0, NULL) < 0 ) - return PyErr_SetFromErrno(xc_error); - - Py_INCREF(zero); - return zero; -} - -static PyObject *pyxc_rrobin_global_get(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - u64 slice; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - if ( xc_rrobin_global_get(xc->xc_handle, &slice) != 0 ) - return PyErr_SetFromErrno(xc_error); - - return Py_BuildValue("{s:L}", "slice", slice); -} - -static PyObject *pyxc_domain_setname(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - u32 dom; - char *name; - - static char *kwd_list[] = { "dom", "name", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "is", kwd_list, - &dom, &name) ) - return NULL; - - if ( xc_domain_setname(xc->xc_handle, dom, name) != 0 ) - return PyErr_SetFromErrno(xc_error); - - Py_INCREF(zero); - return zero; -} - -static PyObject *pyxc_domain_setmaxmem(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - u32 dom; - unsigned long max_memkb; - - static char *kwd_list[] = { "dom", "max_memkb", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "ii", kwd_list, - &dom, &max_memkb) ) - return NULL; - - if ( xc_domain_setmaxmem(xc->xc_handle, dom, max_memkb) != 0 ) - return PyErr_SetFromErrno(xc_error); - - Py_INCREF(zero); - return zero; -} - - -static PyMethodDef pyxc_methods[] = { - { "domain_create", - (PyCFunction)pyxc_domain_create, - METH_VARARGS | METH_KEYWORDS, "\n" - "Create a new domain.\n" - " mem_kb [int, 0]: Memory allocation, in kilobytes.\n" - " name [str, '(anon)']: Informative textual name.\n\n" - "Returns: [int] new domain identifier; -1 on error.\n" }, - - { "domain_pause", - (PyCFunction)pyxc_domain_pause, - METH_VARARGS | METH_KEYWORDS, "\n" - "Temporarily pause execution of a domain.\n" - " dom [int]: Identifier of domain to be paused.\n\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - - { "domain_unpause", - (PyCFunction)pyxc_domain_unpause, - METH_VARARGS | METH_KEYWORDS, "\n" - "(Re)start execution of a domain.\n" - " dom [int]: Identifier of domain to be unpaused.\n\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - - { "domain_destroy", - (PyCFunction)pyxc_domain_destroy, - METH_VARARGS | METH_KEYWORDS, "\n" - "Destroy a domain.\n" - " dom [int]: Identifier of domain to be destroyed.\n\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - - { "domain_pincpu", - (PyCFunction)pyxc_domain_pincpu, - METH_VARARGS | METH_KEYWORDS, "\n" - "Pin a domain to a specified CPU.\n" - " dom [int]: Identifier of domain to be pinned.\n" - " cpu [int, -1]: CPU to pin to, or -1 to unpin\n\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - - { "domain_getinfo", - (PyCFunction)pyxc_domain_getinfo, - METH_VARARGS | METH_KEYWORDS, "\n" - "Get information regarding a set of domains, in increasing id order.\n" - " first_dom [int, 0]: First domain to retrieve info about.\n" - " max_doms [int, 1024]: Maximum number of domains to retrieve info" - " about.\n\n" - "Returns: [list of dicts] if list length is less than 'max_doms'\n" - " parameter then there was an error, or the end of the\n" - " domain-id space was reached.\n" - " dom [int]: Identifier of domain to which this info pertains\n" - " cpu [int]: CPU to which this domain is bound\n" - " dying [int]: Bool - is the domain dying?\n" - " crashed [int]: Bool - has the domain crashed?\n" - " shutdown [int]: Bool - has the domain shut itself down?\n" - " paused [int]: Bool - is the domain paused by control software?\n" - " blocked [int]: Bool - is the domain blocked waiting for an event?\n" - " running [int]: Bool - is the domain currently running?\n" - " mem_kb [int]: Memory reservation, in kilobytes\n" - " cpu_time [long]: CPU time consumed, in nanoseconds\n" - " name [str]: Identifying name\n" - " shutdown_reason [int]: Numeric code from guest OS, explaining " - "reason why it shut itself down.\n" }, - - { "linux_save", - (PyCFunction)pyxc_linux_save, - METH_VARARGS | METH_KEYWORDS, "\n" - "Save the CPU and memory state of a Linux guest OS.\n" - " dom [int]: Identifier of domain to be saved.\n" - " state_file [str]: Name of state file. Must not currently exist.\n" - " progress [int, 1]: Bool - display a running progress indication?\n\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - - { "linux_restore", - (PyCFunction)pyxc_linux_restore, - METH_VARARGS | METH_KEYWORDS, "\n" - "Restore the CPU and memory state of a Linux guest OS.\n" - " state_file [str]: Name of state file. Must not currently exist.\n" - " progress [int, 1]: Bool - display a running progress indication?\n\n" - "Returns: [int] new domain identifier on success; -1 on error.\n" }, - - { "linux_build", - (PyCFunction)pyxc_linux_build, - METH_VARARGS | METH_KEYWORDS, "\n" - "Build a new Linux guest OS.\n" - " dom [int]: Identifier of domain to build into.\n" - " image [str]: Name of kernel image file. May be gzipped.\n" - " ramdisk [str, n/a]: Name of ramdisk file, if any.\n" - " cmdline [str, n/a]: Kernel parameters, if any.\n\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - - { "netbsd_build", - (PyCFunction)pyxc_netbsd_build, - METH_VARARGS | METH_KEYWORDS, "\n" - "Build a new NetBSD guest OS.\n" - " dom [int]: Identifier of domain to build into.\n" - " image [str]: Name of kernel image file. May be gzipped.\n" - " cmdline [str, n/a]: Kernel parameters, if any.\n\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - - { "bvtsched_global_set", - (PyCFunction)pyxc_bvtsched_global_set, - METH_VARARGS | METH_KEYWORDS, "\n" - "Set global tuning parameters for Borrowed Virtual Time scheduler.\n" - " ctx_allow [int]: Minimal guaranteed quantum.\n\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - - { "bvtsched_global_get", - (PyCFunction)pyxc_bvtsched_global_get, - METH_KEYWORDS, "\n" - "Get global tuning parameters for BVT scheduler.\n" - "Returns: [dict]:\n" - " ctx_allow [int]: context switch allowance\n" }, - - { "bvtsched_domain_set", - (PyCFunction)pyxc_bvtsched_domain_set, - METH_VARARGS | METH_KEYWORDS, "\n" - "Set per-domain tuning parameters for Borrowed Virtual Time scheduler.\n" - " dom [int]: Identifier of domain to be tuned.\n" - " mcuadv [int]: Proportional to the inverse of the domain's weight.\n" - " warp [int]: How far to warp domain's EVT on unblock.\n" - " warpl [int]: How long the domain can run warped.\n" - " warpu [int]: How long before the domain can warp again.\n\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - - { "bvtsched_domain_get", - (PyCFunction)pyxc_bvtsched_domain_get, - METH_KEYWORDS, "\n" - "Get per-domain tuning parameters under the BVT scheduler.\n" - " dom [int]: Identifier of domain to be queried.\n" - "Returns [dict]:\n" - " domain [int]: Domain ID.\n" - " mcuadv [long]: MCU Advance.\n" - " warp [long]: Warp.\n" - " warpu [long]: Unwarp requirement.\n" - " warpl [long]: Warp limit,\n" - }, - - { "atropos_domain_set", - (PyCFunction)pyxc_atropos_domain_set, - METH_KEYWORDS, "\n" - "Set the scheduling parameters for a domain when running with Atropos.\n" - " dom [int]: domain to set\n" - " period [long]: domain's scheduling period\n" - " slice [long]: domain's slice per period\n" - " latency [long]: wakeup latency hint\n" - " xtratime [int]: boolean\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - - { "atropos_domain_get", - (PyCFunction)pyxc_atropos_domain_get, - METH_KEYWORDS, "\n" - "Get the current scheduling parameters for a domain when running with\n" - "the Atropos scheduler." - " dom [int]: domain to query\n" - "Returns: [dict]\n" - " domain [int]: domain ID\n" - " period [long]: scheduler period\n" - " slice [long]: CPU reservation per period\n" - " latency [long]: unblocking latency hint\n" - " xtratime [int] : 0 if not using slack time, nonzero otherwise\n" }, - - { "rrobin_global_set", - (PyCFunction)pyxc_rrobin_global_set, - METH_KEYWORDS, "\n" - "Set Round Robin scheduler slice.\n" - " slice [long]: Round Robin scheduler slice\n" - "Returns: [int] 0 on success, throws an exception on failure\n" }, - - { "rrobin_global_get", - (PyCFunction)pyxc_rrobin_global_get, - METH_KEYWORDS, "\n" - "Get Round Robin scheduler settings\n" - "Returns [dict]:\n" - " slice [long]: Scheduler time slice.\n" }, - - { "evtchn_bind_interdomain", - (PyCFunction)pyxc_evtchn_bind_interdomain, - METH_VARARGS | METH_KEYWORDS, "\n" - "Open an event channel between two domains.\n" - " dom1 [int, SELF]: First domain to be connected.\n" - " dom2 [int, SELF]: Second domain to be connected.\n\n" - "Returns: [dict] dictionary is empty on failure.\n" - " port1 [int]: Port-id for endpoint at dom1.\n" - " port2 [int]: Port-id for endpoint at dom2.\n" }, - - { "evtchn_bind_virq", - (PyCFunction)pyxc_evtchn_bind_virq, - METH_VARARGS | METH_KEYWORDS, "\n" - "Bind an event channel to the specified VIRQ.\n" - " virq [int]: VIRQ to bind.\n\n" - "Returns: [int] Bound event-channel port.\n" }, - - { "evtchn_close", - (PyCFunction)pyxc_evtchn_close, - METH_VARARGS | METH_KEYWORDS, "\n" - "Close an event channel.\n" - " dom [int, SELF]: Dom-id of one endpoint of the channel.\n" - " port [int]: Port-id of one endpoint of the channel.\n\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - - { "evtchn_send", - (PyCFunction)pyxc_evtchn_send, - METH_VARARGS | METH_KEYWORDS, "\n" - "Send an event along a locally-connected event channel.\n" - " port [int]: Port-id of a local channel endpoint.\n\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - - { "evtchn_status", - (PyCFunction)pyxc_evtchn_status, - METH_VARARGS | METH_KEYWORDS, "\n" - "Query the status of an event channel.\n" - " dom [int, SELF]: Dom-id of one endpoint of the channel.\n" - " port [int]: Port-id of one endpoint of the channel.\n\n" - "Returns: [dict] dictionary is empty on failure.\n" - " status [str]: 'closed', 'unbound', 'interdomain', 'pirq'," - " or 'virq'.\n" - "The following are returned if 'status' is 'interdomain':\n" - " dom [int]: Dom-id of remote endpoint.\n" - " port [int]: Port-id of remote endpoint.\n" - "The following are returned if 'status' is 'pirq' or 'virq':\n" - " irq [int]: IRQ number.\n" }, - - { "physdev_pci_access_modify", - (PyCFunction)pyxc_physdev_pci_access_modify, - METH_VARARGS | METH_KEYWORDS, "\n" - "Allow a domain access to a PCI device\n" - " dom [int]: Identifier of domain to be allowed access.\n" - " bus [int]: PCI bus\n" - " dev [int]: PCI slot\n" - " func [int]: PCI function\n" - " enable [int]: Non-zero means enable access; else disable access\n\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - - { "readconsolering", - (PyCFunction)pyxc_readconsolering, - METH_VARARGS | METH_KEYWORDS, "\n" - "Read Xen's console ring.\n" - " clear [int, 0]: Bool - clear the ring after reading from it?\n\n" - "Returns: [str] string is empty on failure.\n" }, - - { "physinfo", - (PyCFunction)pyxc_physinfo, - METH_VARARGS, "\n" - "Get information about the physical host machine\n" - "Returns [dict]: information about the hardware" - " [None]: on failure.\n" }, - - { "shadow_control", - (PyCFunction)pyxc_shadow_control, - METH_VARARGS | METH_KEYWORDS, "\n" - "Set parameter for shadow pagetable interface\n" - " dom [int]: Identifier of domain.\n" - " op [int, 0]: operation\n\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - - { "domain_setname", - (PyCFunction)pyxc_domain_setname, - METH_VARARGS | METH_KEYWORDS, "\n" - "Set domain informative textual name\n" - " dom [int]: Identifier of domain.\n" - " name [str]: Text string.\n\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - - { "domain_setmaxmem", - (PyCFunction)pyxc_domain_setname, - METH_VARARGS | METH_KEYWORDS, "\n" - "Set a domain's memory limit\n" - " dom [int]: Identifier of domain.\n" - " max_memkb [long]: .\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - - { NULL, NULL, 0, NULL } -}; - - -/* - * Definitions for the 'Xc' module wrapper. - */ - -staticforward PyTypeObject PyXcType; - -static PyObject *PyXc_new(PyObject *self, PyObject *args) -{ - XcObject *xc; - - if ( !PyArg_ParseTuple(args, ":new") ) - return NULL; - - xc = PyObject_New(XcObject, &PyXcType); - - if ( (xc->xc_handle = xc_interface_open()) == -1 ) - { - PyObject_Del((PyObject *)xc); - return PyErr_SetFromErrno(xc_error); - } - - return (PyObject *)xc; -} - -static PyObject *PyXc_getattr(PyObject *obj, char *name) -{ - return Py_FindMethod(pyxc_methods, obj, name); -} - -static void PyXc_dealloc(PyObject *self) -{ - XcObject *xc = (XcObject *)self; - (void)xc_interface_close(xc->xc_handle); - PyObject_Del(self); -} - -static PyTypeObject PyXcType = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "Xc", - sizeof(XcObject), - 0, - PyXc_dealloc, /* tp_dealloc */ - NULL, /* tp_print */ - PyXc_getattr, /* tp_getattr */ - NULL, /* tp_setattr */ - NULL, /* tp_compare */ - NULL, /* tp_repr */ - NULL, /* tp_as_number */ - NULL, /* tp_as_sequence */ - NULL, /* tp_as_mapping */ - NULL /* tp_hash */ -}; - -static PyMethodDef PyXc_methods[] = { - { "new", PyXc_new, METH_VARARGS, "Create a new " XENPKG " object." }, - { NULL, NULL, 0, NULL } -}; - -PyMODINIT_FUNC initxc(void) -{ - PyObject *m, *d; - - m = Py_InitModule(XENPKG, PyXc_methods); - - d = PyModule_GetDict(m); - xc_error = PyErr_NewException(XENPKG ".error", NULL, NULL); - PyDict_SetItemString(d, "error", xc_error); - - zero = PyInt_FromLong(0); -} diff --git a/tools/xc/py/setup.py b/tools/xc/py/setup.py deleted file mode 100644 index 8efe5ca1a0..0000000000 --- a/tools/xc/py/setup.py +++ /dev/null @@ -1,19 +0,0 @@ - -from distutils.core import setup, Extension - -module = Extension("xc", - extra_compile_args = ["-fno-strict-aliasing"], - include_dirs = ["../lib", - "../../../xen/include/hypervisor-ifs", - "../../../linux-xen-sparse/include", - "../../xu/lib", - "../../lib" ], - library_dirs = ["../lib", - "../../lib" ], - libraries = ["xc"], - sources = ["Xc.c"]) - -setup(name = "xc", - version = "2.0", - ext_package = "xen.ext", - ext_modules = [module]) diff --git a/tools/xen/Makefile b/tools/xen/Makefile deleted file mode 100644 index 343a596e90..0000000000 --- a/tools/xen/Makefile +++ /dev/null @@ -1,20 +0,0 @@ - -all: - python setup.py build - -install: all - if [ "$(prefix)" = "" ]; then \ - python setup.py install; \ - elif [ "$(dist)" = "yes" ]; then \ - python setup.py install --home="$(prefix)"; \ - else \ - python setup.py install --root="$(prefix)"; \ - fi - mkdir -p $(prefix)/usr/sbin - install -m0755 xend $(prefix)/usr/sbin - install -m0755 xm $(prefix)/usr/sbin - mkdir -p $(prefix)/etc/xen/xend - install -m0755 vifctl $(prefix)/etc/xen/xend - -clean: - rm -rf build *.pyc *.pyo *.o *.a *~ diff --git a/tools/xen/lib/__init__.py b/tools/xen/lib/__init__.py deleted file mode 100644 index 8d1c8b69c3..0000000000 --- a/tools/xen/lib/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tools/xen/lib/ext/__init__.py b/tools/xen/lib/ext/__init__.py deleted file mode 100644 index 8d1c8b69c3..0000000000 --- a/tools/xen/lib/ext/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tools/xen/lib/util/Brctl.py b/tools/xen/lib/util/Brctl.py deleted file mode 100644 index 9d3eba1e5f..0000000000 --- a/tools/xen/lib/util/Brctl.py +++ /dev/null @@ -1,160 +0,0 @@ -"""Bridge control utilities. -""" -import os -import os.path -import re -import sys - -os.defpath = os.defpath + ':/sbin:/usr/sbin:/usr/local/sbin' -CMD_IFCONFIG = 'ifconfig' -CMD_ROUTE = 'route' -CMD_BRCTL = 'brctl' -CMD_IPTABLES = "iptables" - -opts = None - -class Opts: - - def __init__(self, defaults): - for (k, v) in defaults.items(): - setattr(self, k, v) - pass - -def cmd(p, s): - """Print and execute command 'p' with args 's'. - """ - global opts - c = p + ' ' + s - if opts.verbose: print c - if not opts.dryrun: - os.system(c) - -def vif_bridge_add(params): - """Add the network interface for vif on dom to a bridge. - """ - cmd(CMD_BRCTL, 'addif %(bridge)s %(vif)s' % params) - -def vif_bridge_rem(params): - """Remove the network interface for vif on dom from a bridge. - """ - cmd(CMD_BRCTL, 'delif %(bridge)s %(vif)s' % params) - -def vif_restrict_addr(vif, addr, delete=0): - d = { 'vif': vif, 'addr': addr} - if delete: - d['flag'] = '-D' - else: - d['flag'] = '-A' - cmd(CMD_IPTABLES, '-P FORWARD DROP') - cmd(CMD_IPTABLES, '%(flag)s FORWARD -m physdev --physdev-in %(vif)s -s %(addr)s -j ACCEPT' % d) - cmd(CMD_IPTABLES, '%(flag)s FORWARD -m physdev --physdev-out %(vif)s -d %(addr)s -j ACCEPT' % d) - -def bridge_create(bridge, **kwd): - """Create a bridge. - Defaults hello time to 0, forward delay to 0 and stp off. - """ - cmd(CMD_BRCTL, 'addbr %s' % bridge) - if kwd.get('hello', None) is None: - kwd['hello'] = 0 - if kwd.get('fd', None) is None: - kwd['fd'] = 0 - if kwd.get('stp', None) is None: - kwd['stp'] = 'off' - bridge_set(bridge, **kwd) - -def bridge_set(bridge, hello=None, fd=None, stp=None): - """Set bridge parameters. - """ - if hello is not None: - cmd(CMD_BRCTL, 'sethello %s %d' % (bridge, hello)) - if fd is not None: - cmd(CMD_BRCTL, 'setfd %s %d' % (bridge, fd)) - if stp is not None: - cmd(CMD_BRCTL, 'stp %s %s' % (bridge, stp)) - -def bridge_del(bridge): - """Delete a bridge. - """ - cmd(CMD_BRCTL, 'delbr %s' % bridge) - -def routes(): - """Return a list of the routes. - """ - fin = os.popen(CMD_ROUTE + ' -n', 'r') - routes = [] - for x in fin: - if x.startswith('Kernel'): continue - if x.startswith('Destination'): continue - x = x.strip() - y = x.split() - z = { 'destination': y[0], - 'gateway' : y[1], - 'mask' : y[2], - 'flags' : y[3], - 'metric' : y[4], - 'ref' : y[5], - 'use' : y[6], - 'interface' : y[7] } - routes.append(z) - return routes - -def ifconfig(interface): - """Return the ip config for an interface, - """ - fin = os.popen(CMD_IFCONFIG + ' %s' % interface, 'r') - inetre = re.compile('\s*inet\s*addr:(?P
\S*)\s*Bcast:(?P\S*)\s*Mask:(?P\S*)') - info = None - for x in fin: - m = inetre.match(x) - if not m: continue - info = m.groupdict() - info['interface'] = interface - break - return info - -def reconfigure(interface, bridge): - """Reconfigure an interface to be attached to a bridge, and give the bridge - the IP address etc. from interface. Move the default route to the interface - to the bridge. - - """ - global opts - intf_info = ifconfig(interface) - if not intf_info: - print >>sys.stderr, 'Interface not found:', interface - return - #bridge_info = ifconfig(bridge) - #if not bridge_info: - # print >>sys.stderr, 'Bridge not found:', bridge - # return - route_info = routes() - intf_info['bridge'] = bridge - intf_info['gateway'] = None - for r in route_info: - if (r['destination'] == '0.0.0.0' and - 'G' in r['flags'] and - r['interface'] == interface): - intf_info['gateway'] = r['gateway'] - if not intf_info['gateway']: - print >>sys.stderr, 'Gateway not found: ', interface - return - cmd(CMD_IFCONFIG, - '%(bridge)s %(address)s netmask %(mask)s broadcast %(broadcast)s up' - % intf_info) - cmd(CMD_ROUTE, - 'add default gateway %(gateway)s dev %(bridge)s' - % intf_info) - cmd(CMD_BRCTL, 'addif %(bridge)s %(interface)s' % intf_info) - cmd(CMD_IFCONFIG, '%(interface)s 0.0.0.0' % intf_info) - -defaults = { - 'verbose' : 1, - 'dryrun' : 0, - } - -opts = Opts(defaults) - -def set_opts(val): - global opts - opts = val - return opts diff --git a/tools/xen/lib/util/__init__.py b/tools/xen/lib/util/__init__.py deleted file mode 100644 index 8d1c8b69c3..0000000000 --- a/tools/xen/lib/util/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tools/xen/lib/util/console_client.py b/tools/xen/lib/util/console_client.py deleted file mode 100644 index 7ac63aeb75..0000000000 --- a/tools/xen/lib/util/console_client.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env python - -############################################## -# Console client for Xen guest OSes -# Copyright (c) 2004, K A Fraser -############################################## - -import errno, os, signal, socket, struct, sys - -from termios import * -# Indexes into termios.tcgetattr() list. -IFLAG = 0 -OFLAG = 1 -CFLAG = 2 -LFLAG = 3 -ISPEED = 4 -OSPEED = 5 -CC = 6 - -def __child_death(signum, frame): - global stop - stop = True - -def __recv_from_sock(sock): - global stop - stop = False - while not stop: - try: - data = sock.recv(1024) - os.write(1, data) - except socket.error, error: - if error[0] != errno.EINTR: - raise - os.wait() - -def __send_to_sock(sock): - while 1: - data = os.read(0,1024) - if ord(data[0]) == ord(']')-64: - break - try: - sock.send(data) - except socket.error, error: - if error[0] == errno.EPIPE: - sys.exit(0) - if error[0] != errno.EINTR: - raise - sys.exit(0) - -def connect(host,port): - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) - sock.connect((host,port)) - - oattrs = tcgetattr(0) - nattrs = tcgetattr(0) - nattrs[IFLAG] = nattrs[IFLAG] & ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON) - nattrs[OFLAG] = nattrs[OFLAG] & ~(OPOST) - nattrs[CFLAG] = nattrs[CFLAG] & ~(CSIZE | PARENB) - nattrs[CFLAG] = nattrs[CFLAG] | CS8 - nattrs[LFLAG] = nattrs[LFLAG] & ~(ECHO | ICANON | IEXTEN | ISIG) - nattrs[CC][VMIN] = 1 - nattrs[CC][VTIME] = 0 - - if os.fork(): - signal.signal(signal.SIGCHLD, __child_death) - print "************ REMOTE CONSOLE: CTRL-] TO QUIT ********" - tcsetattr(0, TCSAFLUSH, nattrs) - try: - __recv_from_sock(sock) - finally: - tcsetattr(0, TCSAFLUSH, oattrs) - print - print "************ REMOTE CONSOLE EXITED *****************" - else: - signal.signal(signal.SIGPIPE, signal.SIG_IGN) - __send_to_sock(sock) - -if __name__ == '__main__': - if len(sys.argv) != 3: - print sys.argv[0] + " " - sys.exit(1) - connect(str(sys.argv[1]),int(sys.argv[2])) diff --git a/tools/xen/lib/util/ip.py b/tools/xen/lib/util/ip.py deleted file mode 100644 index 8396e0d014..0000000000 --- a/tools/xen/lib/util/ip.py +++ /dev/null @@ -1,113 +0,0 @@ -import os -import re -import socket -import struct - -def readlines(fd): - """Version of readlines safe against EINTR. - """ - import errno - - lines = [] - while 1: - try: - line = fd.readline() - except IOError, ex: - if ex.errno == errno.EINTR: - continue - else: - raise - if line == '': break - lines.append(line) - return lines - -def readline(fd): - """Version of readline safe against EINTR. - """ - while 1: - try: - return fd.readline() - except IOError, ex: - if ex.errno == errno.EINTR: - continue - else: - raise - -##### Networking-related functions - -"""Bridge for network backend. -When bridging is used, eth0 may not have an IP address, -as it may have been moved onto the bridge. -""" -NBE_BRIDGE = 'nbe-br' - -def get_current_ipaddr(dev='eth0'): - """Return a string containing the primary IP address for the given - network interface (default 'eth0'). - """ - fd = os.popen( '/sbin/ifconfig ' + dev + ' 2>/dev/null' ) - lines = readlines(fd) - for line in lines: - m = re.search( '^\s+inet addr:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*', - line ) - if m: - return m.group(1) - if dev == 'eth0': - return get_current_ipaddr(NBE_BRIDGE) - return None - -def get_current_ipmask(dev='eth0'): - """Return a string containing the primary IP netmask for the given - network interface (default 'eth0'). - """ - fd = os.popen( '/sbin/ifconfig ' + dev + ' 2>/dev/null' ) - lines = readlines(fd) - for line in lines: - m = re.search( '^.+Mask:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*', - line ) - if m: - return m.group(1) - if dev == 'eth0': - return get_current_ipmask(NBE_BRIDGE) - return None - -def get_current_ipgw(dev='eth0'): - """Return a string containing the IP gateway for the given - network interface (default 'eth0'). - """ - fd = os.popen( '/sbin/route -n' ) - lines = readlines(fd) - for line in lines: - m = re.search( '^\S+\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)' + - '\s+\S+\s+\S*G.*' + dev + '.*', line ) - if m: - return m.group(1) - if dev == 'eth0': - return get_current_ipgw(NBE_BRIDGE) - return None - -def inet_aton(addr): - """Convert an IP addr in IPv4 dot notation into an int. - """ - b = socket.inet_aton(addr) - return struct.unpack('!I', b)[0] - -def inet_ntoa(n): - """Convert an int into an IP addr in IPv4 dot notation. - """ - b = struct.pack('!I', n) - return socket.inet_ntoa(b) - -def add_offset_to_ip(addr, offset): - """Add a numerical offset to an IP addr in IPv4 dot notation. - """ - n = inet_aton(addr) - n += offset - return inet_ntoa(n) - -def check_subnet( ip, network, netmask ): - n_ip = inet_aton(ip) - n_net = inet_aton(network) - n_mask = inet_aton(netmask) - return (n_ip & n_mask) == (n_net & n_mask) - diff --git a/tools/xen/lib/util/tempfile.py b/tools/xen/lib/util/tempfile.py deleted file mode 100644 index 756d8c8727..0000000000 --- a/tools/xen/lib/util/tempfile.py +++ /dev/null @@ -1,451 +0,0 @@ -"""Temporary files. - -This module provides generic, low- and high-level interfaces for -creating temporary files and directories. The interfaces listed -as "safe" just below can be used without fear of race conditions. -Those listed as "unsafe" cannot, and are provided for backward -compatibility only. - -This module also provides some data items to the user: - - TMP_MAX - maximum number of names that will be tried before - giving up. - template - the default prefix for all temporary names. - You may change this to control the default prefix. - tempdir - If this is set to a string before the first use of - any routine from this module, it will be considered as - another candidate location to store temporary files. -""" - -__all__ = [ - "NamedTemporaryFile", "TemporaryFile", # high level safe interfaces - "mkstemp", "mkdtemp", # low level safe interfaces - "mktemp", # deprecated unsafe interface - "TMP_MAX", "gettempprefix", # constants - "tempdir", "gettempdir" - ] - - -# Imports. - -import os as _os -import errno as _errno -from random import Random as _Random - -if _os.name == 'mac': - import Carbon.Folder as _Folder - import Carbon.Folders as _Folders - -try: - import fcntl as _fcntl - # If PYTHONCASEOK is set on Windows, stinking FCNTL.py gets - # imported, and we don't get an ImportError then. Provoke - # an AttributeError instead in that case. - _fcntl.fcntl -except (ImportError, AttributeError): - def _set_cloexec(fd): - pass -else: - def _set_cloexec(fd): - flags = _fcntl.fcntl(fd, _fcntl.F_GETFD, 0) - if flags >= 0: - # flags read successfully, modify - flags |= _fcntl.FD_CLOEXEC - _fcntl.fcntl(fd, _fcntl.F_SETFD, flags) - - -try: - import thread as _thread -except ImportError: - import dummy_thread as _thread -_allocate_lock = _thread.allocate_lock - -_text_openflags = _os.O_RDWR | _os.O_CREAT | _os.O_EXCL -if hasattr(_os, 'O_NOINHERIT'): - _text_openflags |= _os.O_NOINHERIT -if hasattr(_os, 'O_NOFOLLOW'): - _text_openflags |= _os.O_NOFOLLOW - -_bin_openflags = _text_openflags -if hasattr(_os, 'O_BINARY'): - _bin_openflags |= _os.O_BINARY - -if hasattr(_os, 'TMP_MAX'): - TMP_MAX = _os.TMP_MAX -else: - TMP_MAX = 10000 - -template = "tmp" - -tempdir = None - -# Internal routines. - -_once_lock = _allocate_lock() - -class _RandomNameSequence: - """An instance of _RandomNameSequence generates an endless - sequence of unpredictable strings which can safely be incorporated - into file names. Each string is six characters long. Multiple - threads can safely use the same instance at the same time. - - _RandomNameSequence is an iterator.""" - - characters = ("abcdefghijklmnopqrstuvwxyz" + - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + - "0123456789-_") - - def __init__(self): - self.mutex = _allocate_lock() - self.rng = _Random() - self.normcase = _os.path.normcase - - def __iter__(self): - return self - - def next(self): - m = self.mutex - c = self.characters - choose = self.rng.choice - - m.acquire() - try: - letters = [choose(c) for dummy in "123456"] - finally: - m.release() - - return self.normcase(''.join(letters)) - -def _candidate_tempdir_list(): - """Generate a list of candidate temporary directories which - _get_default_tempdir will try.""" - - dirlist = [] - - # First, try the environment. - for envname in 'TMPDIR', 'TEMP', 'TMP': - dirname = _os.getenv(envname) - if dirname: dirlist.append(dirname) - - # Failing that, try OS-specific locations. - if _os.name == 'mac': - try: - fsr = _Folder.FSFindFolder(_Folders.kOnSystemDisk, - _Folders.kTemporaryFolderType, 1) - dirname = fsr.as_pathname() - dirlist.append(dirname) - except _Folder.error: - pass - elif _os.name == 'riscos': - dirname = _os.getenv('Wimp$ScrapDir') - if dirname: dirlist.append(dirname) - elif _os.name == 'nt': - dirlist.extend([ r'c:\temp', r'c:\tmp', r'\temp', r'\tmp' ]) - else: - dirlist.extend([ '/tmp', '/var/tmp', '/usr/tmp' ]) - - # As a last resort, the current directory. - try: - dirlist.append(_os.getcwd()) - except (AttributeError, _os.error): - dirlist.append(_os.curdir) - - return dirlist - -def _get_default_tempdir(): - """Calculate the default directory to use for temporary files. - This routine should be called exactly once. - - We determine whether or not a candidate temp dir is usable by - trying to create and write to a file in that directory. If this - is successful, the test file is deleted. To prevent denial of - service, the name of the test file must be randomized.""" - - namer = _RandomNameSequence() - dirlist = _candidate_tempdir_list() - flags = _text_openflags - - for dir in dirlist: - if dir != _os.curdir: - dir = _os.path.normcase(_os.path.abspath(dir)) - # Try only a few names per directory. - for seq in xrange(100): - name = namer.next() - filename = _os.path.join(dir, name) - try: - fd = _os.open(filename, flags, 0600) - fp = _os.fdopen(fd, 'w') - fp.write('blat') - fp.close() - _os.unlink(filename) - del fp, fd - return dir - except (OSError, IOError), e: - if e[0] != _errno.EEXIST: - break # no point trying more names in this directory - pass - raise IOError, (_errno.ENOENT, - ("No usable temporary directory found in %s" % dirlist)) - -_name_sequence = None - -def _get_candidate_names(): - """Common setup sequence for all user-callable interfaces.""" - - global _name_sequence - if _name_sequence is None: - _once_lock.acquire() - try: - if _name_sequence is None: - _name_sequence = _RandomNameSequence() - finally: - _once_lock.release() - return _name_sequence - - -def _mkstemp_inner(dir, pre, suf, flags): - """Code common to mkstemp, TemporaryFile, and NamedTemporaryFile.""" - - names = _get_candidate_names() - - for seq in xrange(TMP_MAX): - name = names.next() - file = _os.path.join(dir, pre + name + suf) - try: - fd = _os.open(file, flags, 0600) - _set_cloexec(fd) - return (fd, file) - except OSError, e: - if e.errno == _errno.EEXIST: - continue # try again - raise - - raise IOError, (_errno.EEXIST, "No usable temporary file name found") - - -# User visible interfaces. - -def gettempprefix(): - """Accessor for tempdir.template.""" - return template - -tempdir = None - -def gettempdir(): - """Accessor for tempdir.tempdir.""" - global tempdir - if tempdir is None: - _once_lock.acquire() - try: - if tempdir is None: - tempdir = _get_default_tempdir() - finally: - _once_lock.release() - return tempdir - -def mkstemp(suffix="", prefix=template, dir=None, text=False): - """mkstemp([suffix, [prefix, [dir, [text]]]]) - User-callable function to create and return a unique temporary - file. The return value is a pair (fd, name) where fd is the - file descriptor returned by os.open, and name is the filename. - - If 'suffix' is specified, the file name will end with that suffix, - otherwise there will be no suffix. - - If 'prefix' is specified, the file name will begin with that prefix, - otherwise a default prefix is used. - - If 'dir' is specified, the file will be created in that directory, - otherwise a default directory is used. - - If 'text' is specified and true, the file is opened in text - mode. Else (the default) the file is opened in binary mode. On - some operating systems, this makes no difference. - - The file is readable and writable only by the creating user ID. - If the operating system uses permission bits to indicate whether a - file is executable, the file is executable by no one. The file - descriptor is not inherited by children of this process. - - Caller is responsible for deleting the file when done with it. - """ - - if dir is None: - dir = gettempdir() - - if text: - flags = _text_openflags - else: - flags = _bin_openflags - - return _mkstemp_inner(dir, prefix, suffix, flags) - - -def mkdtemp(suffix="", prefix=template, dir=None): - """mkdtemp([suffix, [prefix, [dir]]]) - User-callable function to create and return a unique temporary - directory. The return value is the pathname of the directory. - - Arguments are as for mkstemp, except that the 'text' argument is - not accepted. - - The directory is readable, writable, and searchable only by the - creating user. - - Caller is responsible for deleting the directory when done with it. - """ - - if dir is None: - dir = gettempdir() - - names = _get_candidate_names() - - for seq in xrange(TMP_MAX): - name = names.next() - file = _os.path.join(dir, prefix + name + suffix) - try: - _os.mkdir(file, 0700) - return file - except OSError, e: - if e.errno == _errno.EEXIST: - continue # try again - raise - - raise IOError, (_errno.EEXIST, "No usable temporary directory name found") - -def mktemp(suffix="", prefix=template, dir=None): - """mktemp([suffix, [prefix, [dir]]]) - User-callable function to return a unique temporary file name. The - file is not created. - - Arguments are as for mkstemp, except that the 'text' argument is - not accepted. - - This function is unsafe and should not be used. The file name - refers to a file that did not exist at some point, but by the time - you get around to creating it, someone else may have beaten you to - the punch. - """ - -## from warnings import warn as _warn -## _warn("mktemp is a potential security risk to your program", -## RuntimeWarning, stacklevel=2) - - if dir is None: - dir = gettempdir() - - names = _get_candidate_names() - for seq in xrange(TMP_MAX): - name = names.next() - file = _os.path.join(dir, prefix + name + suffix) - if not _os.path.exists(file): - return file - - raise IOError, (_errno.EEXIST, "No usable temporary filename found") - -class _TemporaryFileWrapper: - """Temporary file wrapper - - This class provides a wrapper around files opened for - temporary use. In particular, it seeks to automatically - remove the file when it is no longer needed. - """ - - def __init__(self, file, name): - self.file = file - self.name = name - self.close_called = False - - def __getattr__(self, name): - file = self.__dict__['file'] - a = getattr(file, name) - if type(a) != type(0): - setattr(self, name, a) - return a - - # NT provides delete-on-close as a primitive, so we don't need - # the wrapper to do anything special. We still use it so that - # file.name is useful (i.e. not "(fdopen)") with NamedTemporaryFile. - if _os.name != 'nt': - - # Cache the unlinker so we don't get spurious errors at - # shutdown when the module-level "os" is None'd out. Note - # that this must be referenced as self.unlink, because the - # name TemporaryFileWrapper may also get None'd out before - # __del__ is called. - unlink = _os.unlink - - def close(self): - if not self.close_called: - self.close_called = True - self.file.close() - self.unlink(self.name) - - def __del__(self): - self.close() - -def NamedTemporaryFile(mode='w+b', bufsize=-1, suffix="", - prefix=template, dir=None): - """Create and return a temporary file. - Arguments: - 'prefix', 'suffix', 'dir' -- as for mkstemp. - 'mode' -- the mode argument to os.fdopen (default "w+b"). - 'bufsize' -- the buffer size argument to os.fdopen (default -1). - The file is created as mkstemp() would do it. - - Returns a file object; the name of the file is accessible as - file.name. The file will be automatically deleted when it is - closed. - """ - - if dir is None: - dir = gettempdir() - - if 'b' in mode: - flags = _bin_openflags - else: - flags = _text_openflags - - # Setting O_TEMPORARY in the flags causes the OS to delete - # the file when it is closed. This is only supported by Windows. - if _os.name == 'nt': - flags |= _os.O_TEMPORARY - - (fd, name) = _mkstemp_inner(dir, prefix, suffix, flags) - file = _os.fdopen(fd, mode, bufsize) - return _TemporaryFileWrapper(file, name) - -if _os.name != 'posix' or _os.sys.platform == 'cygwin': - # On non-POSIX and Cygwin systems, assume that we cannot unlink a file - # while it is open. - TemporaryFile = NamedTemporaryFile - -else: - def TemporaryFile(mode='w+b', bufsize=-1, suffix="", - prefix=template, dir=None): - """Create and return a temporary file. - Arguments: - 'prefix', 'suffix', 'directory' -- as for mkstemp. - 'mode' -- the mode argument to os.fdopen (default "w+b"). - 'bufsize' -- the buffer size argument to os.fdopen (default -1). - The file is created as mkstemp() would do it. - - Returns a file object. The file has no name, and will cease to - exist when it is closed. - """ - - if dir is None: - dir = gettempdir() - - if 'b' in mode: - flags = _bin_openflags - else: - flags = _text_openflags - - (fd, name) = _mkstemp_inner(dir, prefix, suffix, flags) - try: - _os.unlink(name) - return _os.fdopen(fd, mode, bufsize) - except: - _os.close(fd) - raise diff --git a/tools/xen/lib/xend/Args.py b/tools/xen/lib/xend/Args.py deleted file mode 100644 index 527e841d3d..0000000000 --- a/tools/xen/lib/xend/Args.py +++ /dev/null @@ -1,126 +0,0 @@ -import sxp - -class ArgError(StandardError): - pass - -class Args: - """Argument encoding support for HTTP. - """ - - def __init__(self, paramspec, keyspec): - self.arg_ord = [] - self.arg_dict = {} - self.key_ord = [] - self.key_dict = {} - for (name, type) in paramspec: - self.arg_ord.append(name) - self.arg_dict[name] = type - for (name, type) in keyspec: - self.key_ord.append(name) - self.key_dict[name] = type - - def get_args(self, d, xargs=None): - args = {} - keys = {} - params = [] - if xargs: - self.split_args(xargs, args, keys) - self.split_args(d, args, keys) - for a in self.arg_ord: - if a in args: - params.append(args[a]) - else: - raise ArgError('Missing parameter: %s' % a) - return (params, keys) - - def split_args(self, d, args, keys): - for (k, v) in d.items(): - if k in self.arg_dict: - type = self.arg_dict[k] - val = self.coerce(type, v) - args[k] = val - elif k in self.key_dict: - type = self.key_dict[k] - val = self.coerce(type, v) - keys[k] = val - else: - raise ArgError('Invalid parameter: %s' % k) - - def get_form_args(self, f, xargs=None): - d = {} - for (k, v) in f.items(): - n = len(v) - if ((k not in self.arg_dict) and - (k not in self.key_dict)): - continue - if n == 0: - continue - elif n == 1: - d[k] = v[0] - else: - raise ArgError('Too many values for %s' % k) - return self.get_args(d, xargs=xargs) - - def coerce(self, type, v): - try: - if type == 'int': - return int(v) - if type == 'str': - return str(v) - if type == 'sxpr': - return self.sxpr(v) - except ArgError: - raise - except StandardError, ex: - raise ArgError(str(ex)) - - def sxpr(self, v): - if instanceof(v, types.ListType): - return v - if instanceof(v, types.File) or hasattr(v, 'readline'): - return sxpr_file(v) - if instanceof(v, types.StringType): - return sxpr_file(StringIO(v)) - return str(v) - - def sxpr_file(self, fin): - try: - vals = sxp.parse(fin) - except: - raise ArgError('Coercion to sxpr failed') - if len(vals) == 1: - return vals[0] - else: - raise ArgError('Too many sxprs') - - def call_with_args(self, fn, args, xargs=None): - (params, keys) = self.get_args(args, xargs=xargs) - fn(*params, **keys) - - def call_with_form_args(self, fn, fargs, xargs=None): - (params, keys) = self.get_form_args(fargs, xargs=xargs) - fn(*params, **keys) - -class ArgFn(Args): - """Represent a remote HTTP operation as a function. - Used on the client. - """ - - def __init__(self, fn, paramspec, keyspec={}): - Args.__init__(self, paramspec, keyspec) - self.fn = fn - - def __call__(self, fargs, xargs=None): - return self.call_with_args(self.fn, fargs, xargs=xargs) - -class FormFn(Args): - """Represent an operation as a function over a form. - Used in the HTTP server. - """ - - def __init__(self, fn, paramspec, keyspec={}): - Args.__init__(self, paramspec, keyspec) - self.fn = fn - - def __call__(self, fargs, xargs=None): - return self.call_with_form_args(self.fn, fargs, xargs=xargs) diff --git a/tools/xen/lib/xend/EventServer.py b/tools/xen/lib/xend/EventServer.py deleted file mode 100644 index 20c567ada7..0000000000 --- a/tools/xen/lib/xend/EventServer.py +++ /dev/null @@ -1,215 +0,0 @@ -# Copyright (C) 2004 Mike Wray -"""Simple publish/subscribe event server. - -""" -import string - -from twisted.internet import reactor - -# subscribe a.b.c h: map a.b.c -> h -# subscribe a.b.* h: map a.b.* -> h -# subscribe a.b.? h: map a.b.? -> h -# -# for event a.b.c.d: -# -# lookup a.b.c.d, call handlers -# -# lookup a.b.c.?, call handlers -# -# lookup a.b.c.d.*, call handlers -# lookup a.b.c.*, call handlers -# lookup a.b.*, call handlers -# lookup a.*, call handlers -# lookup *, call handlers - -# a.b.c.d = (a b c d) -# a.b.c.? = (a b c _) -# a.b.c.* = (a b c . _) - -class EventServer: - - DOT = '.' - QUERY = '?' - DOT_QUERY = DOT + QUERY - STAR = '*' - DOT_STAR = DOT + STAR - - def __init__(self, run=0): - self.handlers = {} - self.run = run - self.queue = [] - - def start(self): - """Enable event handling. Sends any queued events. - """ - self.run = 1 - for (e,v) in self.queue: - self.inject(e, v) - self.queue = [] - - def stop(self): - """Suspend event handling. Events injected while suspended - are queued until we are started again. - """ - self.run = 0 - - def subscribe(self, event, handler): - """Subscribe to an event. For example 'a.b.c.d'. - A subcription like 'a.b.c.?' ending in '?' matches any value - for the '?'. A subscription like 'a.b.c.*' ending in '*' matches - any event type with the same prefix, 'a.b.c' in this case. - - event event name - handler event handler fn(event, val) - """ - hl = self.handlers.get(event) - if hl is None: - self.handlers[event] = [handler] - else: - hl.append(handler) - - def unsubscribe_all(self, event=None): - """Unsubscribe all handlers for a given event, or all handlers. - - event event (optional) - """ - if event == None: - self.handlers.clear() - elif event in self.handlers: - del self.handlers[event] - - def unsubscribe(self, event, handler): - """Unsubscribe a given event and handler. - - event event - handler handler - """ - hl = self.handlers.get(event) - if hl is None: - return - if handler in hl: - hl.remove(handler) - - def inject(self, event, val, async=1): - """Inject an event. Handlers for it are called if running, otherwise - it is queued. - - event event type - val event value - """ - if self.run: - if async: - reactor.callLater(0, self.call_handlers, event, val) - else: - self.notify_handlers(event, val) - else: - self.queue.append( (event, val) ) - - def call_handlers(self, event, val): - """Internal method to call event handlers. - """ - #print ">event", event, val - self.call_event_handlers(event, event, val) - self.call_query_handlers(event, val) - self.call_star_handlers(event, val) - - def call_event_handlers(self, key, event, val): - """Call the handlers for an event. - It is safe for handlers to subscribe or unsubscribe. - - key key for handler list - event event type - val event value - """ - hl = self.handlers.get(key) - if hl is None: - return - # Copy the handler list so that handlers can call - # subscribe/unsubscribe safely - python list iteration - # is not safe against list modification. - for h in hl[:]: - try: - h(event, val) - except: - pass - - def call_query_handlers(self, event, val): - """Call regex handlers for events matching 'event' that end in '?'. - - event event type - val event value - """ - dot_idx = event.rfind(self.DOT) - if dot_idx == -1: - self.call_event_handlers(self.QUERY, event, val) - else: - event_query = event[0:dot_idx] + self.DOT_QUERY - self.call_event_handlers(event_query, event, val) - - def call_star_handlers(self, event, val): - """Call regex handlers for events matching 'event' that end in '*'. - - event event type - val event value - """ - etype = string.split(event, self.DOT) - for i in range(len(etype), 0, -1): - event_star = self.DOT.join(etype[0:i]) + self.DOT_STAR - self.call_event_handlers(event_star, event, val) - self.call_event_handlers(self.STAR, event, val) - -def instance(): - global inst - try: - inst - except: - inst = EventServer() - inst.start() - return inst - -def main(): - def sys_star(event, val): - print 'sys_star', event, val - - def sys_foo(event, val): - print 'sys_foo', event, val - s.unsubscribe('sys.foo', sys_foo) - - def sys_foo2(event, val): - print 'sys_foo2', event, val - - def sys_bar(event, val): - print 'sys_bar', event, val - - def sys_foo_bar(event, val): - print 'sys_foo_bar', event, val - - def foo_bar(event, val): - print 'foo_bar', event, val - - s = EventServer() - s.start() - s.subscribe('sys.*', sys_star) - s.subscribe('sys.foo', sys_foo) - s.subscribe('sys.foo', sys_foo2) - s.subscribe('sys.bar', sys_bar) - s.subscribe('sys.foo.bar', sys_foo_bar) - s.subscribe('foo.bar', foo_bar) - s.inject('sys.foo', 'hello') - print - s.inject('sys.bar', 'hello again') - print - s.inject('sys.foo.bar', 'hello again') - print - s.inject('foo.bar', 'hello again') - print - s.inject('foo', 'hello again') - print - s.start() - s.unsubscribe('sys.*', sys_star) - s.unsubscribe_all('sys.*') - s.inject('sys.foo', 'hello') - -if __name__ == "__main__": - main() - diff --git a/tools/xen/lib/xend/EventTypes.py b/tools/xen/lib/xend/EventTypes.py deleted file mode 100644 index 6350baa5dd..0000000000 --- a/tools/xen/lib/xend/EventTypes.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright (C) 2004 Mike Wray - -## XEND_DOMAIN_CREATE = "xend.domain.create": dom -## create: -## xend.domain.destroy: dom, reason:died/crashed -## xend.domain.up ? - -## xend.domain.unpause: dom -## xend.domain.pause: dom -## xend.domain.shutdown: dom -## xend.domain.destroy: dom - -## xend.domain.migrate.begin: dom, to -## Begin tells: src host, src domain uri, dst host. Dst id known? -## err: src host, src domain uri, dst host, dst id if known, status (of domain: ok, dead,...), reason -## end: src host, src domain uri, dst host, dst uri - -## Events for both ends of migrate: for exporter and importer? -## Include migrate id so can tie together. -## Have uri /xend/migrate/ for migrate info (migrations in progress). - -## (xend.domain.migrate.begin (src ) (src.domain ) -## (dst ) (id )) - -## xend.domain.migrate.end: -## (xend.domain.migrate.end (domain ) (to ) - -## xend.node.up: xend uri -## xend.node.down: xend uri - -## xend.error ? - -## format: - diff --git a/tools/xen/lib/xend/PrettyPrint.py b/tools/xen/lib/xend/PrettyPrint.py deleted file mode 100644 index 9e91b11448..0000000000 --- a/tools/xen/lib/xend/PrettyPrint.py +++ /dev/null @@ -1,299 +0,0 @@ -# Copyright (C) 2004 Mike Wray - -"""General pretty-printer, including support for SXP. - -""" -import sys -import types -import StringIO -import sxp - -class PrettyItem: - - def __init__(self, width): - self.width = width - - def insert(self, block): - block.addtoline(self) - - def get_width(self): - return self.width - - def output(self, out): - print '***PrettyItem>output>', self - pass - - def prettyprint(self, out, width): - print '***PrettyItem>prettyprint>', self - return width - -class PrettyString(PrettyItem): - - def __init__(self, x): - PrettyItem.__init__(self, len(x)) - self.value = x - - def output(self, out): - out.write(self.value) - - def prettyprint(self, line): - line.output(self) - - def show(self, out): - print >> out, ("(string (width %d) '%s')" % (self.width, self.value)) - -class PrettySpace(PrettyItem): - - def output(self, out): - out.write(' ' * self.width) - - def prettyprint(self, line): - line.output(self) - - def show(self, out): - print >> out, ("(space (width %d))" % self.width) - -class PrettyBreak(PrettyItem): - - def __init__(self, width, indent): - PrettyItem.__init__(self, width) - self.indent = indent - self.space = 0 - self.active = 0 - - def output(self, out): - out.write(' ' * self.width) - - def prettyprint(self, line): - if line.breaks(self.space): - self.active = 1 - line.newline(self.indent) - else: - line.output(self) - - def show(self, out): - print >> out, ("(break (width %d) (indent %d) (space %d) (active %d))" - % (self.width, self.indent, self.space, self.lspace, self.active)) - -class PrettyNewline(PrettySpace): - - def __init__(self, indent): - PrettySpace.__init__(self, indent) - - def insert(self, block): - block.newline() - block.addtoline(self) - - def output(self, out): - out.write(' ' * self.width) - - def prettyprint(self, line): - line.newline(0) - line.output(self) - - def show(self, out): - print >> out, ("(nl (indent %d))" % self.indent) - -class PrettyLine(PrettyItem): - def __init__(self): - PrettyItem.__init__(self, 0) - self.content = [] - - def write(self, x): - self.content.append(x) - - def end(self): - width = 0 - lastwidth = 0 - lastbreak = None - for x in self.content: - if isinstance(x, PrettyBreak): - if lastbreak: - lastbreak.space = (width - lastwidth) - lastbreak = x - lastwidth = width - width += x.get_width() - if lastbreak: - lastbreak.space = (width - lastwidth) - self.width = width - - def prettyprint(self, line): - for x in self.content: - x.prettyprint(line) - - def show(self, out): - print >> out, '(LINE (width %d)' % self.width - for x in self.content: - x.show(out) - print >> out, ')' - -class PrettyBlock(PrettyItem): - - def __init__(self, all=0, parent=None): - self.width = 0 - self.lines = [] - self.parent = parent - self.indent = 0 - self.all = all - self.broken = 0 - self.newline() - - def add(self, item): - item.insert(self) - - def end(self): - self.width = 0 - for l in self.lines: - l.end() - if self.width < l.width: - self.width = l.width - - def breaks(self, n): - return self.all and self.broken - - def newline(self): - self.lines.append(PrettyLine()) - - def addtoline(self, x): - self.lines[-1].write(x) - - def prettyprint(self, line): - self.indent = line.used - line.block = self - if not line.fits(self.width): - self.broken = 1 - for l in self.lines: - l.prettyprint(line) - line.block = self.parent - - def show(self, out): - print >> out, ('(BLOCK (width %d) (indent %d) (all %d) (broken %d)' % - (self.width, self.indent, self.all, self.broken)) - for l in self.lines: - l.show(out) - print >> out, ')' - -class Line: - - def __init__(self, out, width): - self.out = out - self.width = width - self.used = 0 - self.space = self.width - - def newline(self, indent): - indent += self.block.indent - self.out.write('\n') - self.out.write(' ' * indent) - self.used = indent - self.space = self.width - self.used - - def fits(self, n): - return self.space - n >= 0 - - def breaks(self, n): - return self.block.breaks(n) or not self.fits(n) - - def output(self, x): - n = x.get_width() - self.space -= n - self.used += n - if self.space < 0: - self.space = 0 - x.output(self.out) - -class PrettyPrinter: - """A prettyprinter based on what I remember of Derek Oppen's - prettyprint algorithm from TOPLAS way back. - """ - - def __init__(self, width=40): - self.width = width - self.block = None - self.top = None - - def write(self, x): - self.block.add(PrettyString(x)) - - def add(self, item): - self.block.add(item) - - def addbreak(self, width=1, indent=4): - self.add(PrettyBreak(width, indent)) - - def addspace(self, width=1): - self.add(PrettySpace(width)) - - def addnl(self, indent=0): - self.add(PrettyNewline(indent)) - - def begin(self, all=0): - block = PrettyBlock(all=all, parent=self.block) - self.block = block - - def end(self): - self.block.end() - if self.block.parent: - self.block.parent.add(self.block) - else: - self.top = self.block - self.block = self.block.parent - - def prettyprint(self, out=sys.stdout): - line = Line(out, self.width) - self.top.prettyprint(line) - -class SXPPrettyPrinter(PrettyPrinter): - """An SXP prettyprinter. - """ - - def pstring(self, x): - io = StringIO.StringIO() - sxp.show(x, out=io) - io.seek(0) - val = io.getvalue() - io.close() - return val - - def pprint(self, l): - if isinstance(l, types.ListType): - self.begin(all=1) - self.write('(') - i = 0 - for x in l: - if(i): self.addbreak() - self.pprint(x) - i += 1 - self.addbreak(width=0, indent=0) - self.write(')') - self.end() - else: - self.write(self.pstring(l)) - -def prettyprint(sxpr, out=sys.stdout, width=80): - """Prettyprint an SXP form. - - sxpr s-expression - out destination - width maximum output width - """ - if isinstance(sxpr, types.ListType): - pp = SXPPrettyPrinter(width=width) - pp.pprint(sxpr) - pp.prettyprint(out=out) - else: - sxp.show(sxpr, out=out) - print >> out - -def main(): - pin = sxp.Parser() - while 1: - buf = sys.stdin.read(100) - pin.input(buf) - if buf == '': break - l = pin.get_val() - prettyprint(l, width=80) - -if __name__ == "__main__": - main() - diff --git a/tools/xen/lib/xend/Vifctl.py b/tools/xen/lib/xend/Vifctl.py deleted file mode 100644 index 49df8f6bd0..0000000000 --- a/tools/xen/lib/xend/Vifctl.py +++ /dev/null @@ -1,28 +0,0 @@ -import os -import os.path -import sys - -VIFCTL = '/etc/xen/xend/vifctl' - -def init(): - os.system(VIFCTL + ' init ') - -def up(vif, mac=None, bridge=None, ipaddr=[]): - args = ['vif=%s' % vif] - if mac: - args.append('mac=%s' % mac) - if bridge: - args.append('bridge=%s' % bridge) - if ipaddr: - args.append('ipaddr=%s' % ','.join(ipaddr)) - os.system(VIFCTL + ' up ' + ' '.join(args)) - -def down(vif, mac=None, bridge=None, ipaddr=[]): - args = ['vif=%s' % vif] - if mac: - args.append('mac=%s' % mac) - if bridge: - args.append('bridge=%s' % bridge) - if ipaddr: - args.append('ipaddr=%s' % ','.join(ipaddr)) - os.system(VIFCTL + ' down ' + ' '.join(args)) diff --git a/tools/xen/lib/xend/XendClient.py b/tools/xen/lib/xend/XendClient.py deleted file mode 100644 index 13dc3dbb1e..0000000000 --- a/tools/xen/lib/xend/XendClient.py +++ /dev/null @@ -1,311 +0,0 @@ -# Copyright (C) 2004 Mike Wray -"""Client API for the HTTP interface on xend. -Callable as a script - see main(). -""" -import sys -import httplib -import types -from StringIO import StringIO -import urlparse - -from encode import * -import sxp -import PrettyPrint - -DEBUG = 0 - -class Foo(httplib.HTTPResponse): - - def begin(self): - fin = self.fp - while(1): - buf = fin.readline() - print "***", buf - if buf == '': - print - sys.exit() - - -def sxprio(sxpr): - io = StringIO() - sxp.show(sxpr, out=io) - print >> io - io.seek(0) - return io - -def fileof(val): - """Converter for passing configs. - Handles lists, files directly. - Assumes a string is a file name and passes its contents. - """ - if isinstance(val, types.ListType): - return sxprio(val) - if isinstance(val, types.StringType): - return file(val) - if hasattr(val, 'readlines'): - return val - -# todo: need to sort of what urls/paths are using for objects. -# e.g. for domains at the moment return '0'. -# should probably return abs path w.r.t. server, e.g. /xend/domain/0. -# As an arg, assume abs path is obj uri, otherwise just id. - -# Function to convert to full url: Xend.uri(path), e.g. -# maps /xend/domain/0 to http://wray-m-3.hpl.hp.com:8000/xend/domain/0 -# And should accept urls for ids? - -def urljoin(location, root, prefix='', rest=''): - prefix = str(prefix) - rest = str(rest) - base = 'http://' + location + root + prefix - url = urlparse.urljoin(base, rest) - return url - -def nodeurl(location, root, id=''): - return urljoin(location, root, 'node/', id) - -def domainurl(location, root, id=''): - return urljoin(location, root, 'domain/', id) - -def consoleurl(location, root, id=''): - return urljoin(location, root, 'console/', id) - -def deviceurl(location, root, id=''): - return urljoin(location, root, 'device/', id) - -def vneturl(location, root, id=''): - return urljoin(location, root, 'vnet/', id) - -def eventurl(location, root, id=''): - return urljoin(location, root, 'event/', id) - -def xend_request(url, method, data=None): - urlinfo = urlparse.urlparse(url) - (uproto, ulocation, upath, uparam, uquery, ufrag) = urlinfo - if DEBUG: print url, urlinfo - if uproto != 'http': - raise StandardError('Invalid protocol: ' + uproto) - if DEBUG: print '>xend_request', ulocation, upath, method, data - (hdr, args) = encode_data(data) - if data and method == 'GET': - upath += '?' + args - args = None - if method == "POST" and upath.endswith('/'): - upath = upath[:-1] - if DEBUG: print "ulocation=", ulocation, "upath=", upath, "args=", args - #hdr['User-Agent'] = 'Mozilla' - #hdr['Accept'] = 'text/html,text/plain' - conn = httplib.HTTPConnection(ulocation) - #conn.response_class = Foo - if DEBUG: conn.set_debuglevel(1) - conn.request(method, upath, args, hdr) - resp = conn.getresponse() - if DEBUG: print resp.status, resp.reason - if DEBUG: print resp.msg.headers - if resp.status in [204, 404]: - return None - if resp.status not in [200, 201, 202, 203]: - raise RuntimeError(resp.reason) - pin = sxp.Parser() - data = resp.read() - if DEBUG: print "***data" , data - if DEBUG: print "***" - pin.input(data); - pin.input_eof() - conn.close() - val = pin.get_val() - #if isinstance(val, types.ListType) and sxp.name(val) == 'val': - # val = val[1] - if isinstance(val, types.ListType) and sxp.name(val) == 'err': - raise RuntimeError(val[1]) - if DEBUG: print '**val='; sxp.show(val); print - return val - -def xend_get(url, args=None): - return xend_request(url, "GET", args) - -def xend_call(url, data): - return xend_request(url, "POST", data) - -class Xend: - - SRV_DEFAULT = "localhost:8000" - ROOT_DEFAULT = "/xend/" - - def __init__(self, srv=None, root=None): - self.bind(srv, root) - - def bind(self, srv=None, root=None): - if srv is None: srv = self.SRV_DEFAULT - if root is None: root = self.ROOT_DEFAULT - if not root.endswith('/'): root += '/' - self.location = srv - self.root = root - - def nodeurl(self, id=''): - return nodeurl(self.location, self.root, id) - - def domainurl(self, id=''): - return domainurl(self.location, self.root, id) - - def consoleurl(self, id=''): - return consoleurl(self.location, self.root, id) - - def deviceurl(self, id=''): - return deviceurl(self.location, self.root, id) - - def vneturl(self, id=''): - return vneturl(self.location, self.root, id) - - def eventurl(self, id=''): - return eventurl(self.location, self.root, id) - - def xend(self): - return xend_get(urljoin(self.location, self.root)) - - def xend_node(self): - return xend_get(self.nodeurl()) - - def xend_node_cpu_rrobin_slice_set(self, slice): - return xend_call(self.nodeurl(), - {'op' : 'cpu_rrobin_slice_set', - 'slice' : slice }) - - def xend_node_cpu_bvt_slice_set(self, slice): - return xend_call(self.nodeurl(), - {'op' : 'cpu_bvt_slice_set', - 'slice' : slice }) - - def xend_domains(self): - return xend_get(self.domainurl()) - - def xend_domain_create(self, conf): - return xend_call(self.domainurl(), - {'op' : 'create', - 'config' : fileof(conf) }) - - def xend_domain(self, id): - return xend_get(self.domainurl(id)) - - def xend_domain_unpause(self, id): - return xend_call(self.domainurl(id), - {'op' : 'unpause'}) - - def xend_domain_pause(self, id): - return xend_call(self.domainurl(id), - {'op' : 'pause'}) - - def xend_domain_shutdown(self, id): - return xend_call(self.domainurl(id), - {'op' : 'shutdown'}) - - def xend_domain_destroy(self, id): - return xend_call(self.domainurl(id), - {'op' : 'destroy'}) - - def xend_domain_save(self, id, filename): - return xend_call(self.domainurl(id), - {'op' : 'save', - 'file' : filename}) - - def xend_domain_restore(self, id, filename): - return xend_call(self.domainurl(id), - {'op' : 'restore', - 'file' : filename }) - - def xend_domain_migrate(self, id, dst): - return xend_call(self.domainurl(id), - {'op' : 'migrate', - 'destination': dst}) - - def xend_domain_pincpu(self, id, cpu): - return xend_call(self.domainurl(id), - {'op' : 'pincpu', - 'cpu' : cpu}) - - def xend_domain_cpu_bvt_set(self, id, mcuadv, warp, warpl, warpu): - return xend_call(self.domainurl(id), - {'op' : 'cpu_bvt_set', - 'mcuadv' : mvuadv, - 'warp' : warp, - 'warpl' : warpl, - 'warpu' : warpu }) - - def xend_domain_cpu_atropos_set(self, id, period, slice, latency, xtratime): - return xend_call(self.domainurl(id), - {'op' : 'cpu_atropos_set', - 'period' : period, - 'slice' : slice, - 'latency' : latency, - 'xtratime': xtratime }) - - def xend_domain_vifs(self, id): - return xend_get(self.domainurl(id), - { 'op' : 'vifs' }) - - def xend_domain_vif_ip_add(self, id, vif, ipaddr): - return xend_call(self.domainurl(id), - {'op' : 'vif_ip_add', - 'vif' : vif, - 'ip' : ipaddr }) - - def xend_domain_vbds(self, id): - return xend_get(self.domainurl(id), - {'op' : 'vbds'}) - - def xend_domain_vbd(self, id, vbd): - return xend_get(self.domainurl(id), - {'op' : 'vbd', - 'vbd' : vbd}) - - def xend_consoles(self): - return xend_get(self.consoleurl()) - - def xend_console(self, id): - return xend_get(self.consoleurl(id)) - - def xend_vnets(self): - return xend_get(self.vneturl()) - - def xend_vnet_create(self, conf): - return xend_call(self.vneturl(), - {'op': 'create', 'config': fileof(conf) }) - - def xend_vnet(self, id): - return xend_get(self.vneturl(id)) - - def xend_vnet_delete(self, id): - return xend_call(self.vneturl(id), - {'op': 'delete'}) - - def xend_event_inject(self, sxpr): - val = xend_call(self.eventurl(), - {'op': 'inject', 'event': fileof(sxpr) }) - - -def main(argv): - """Call an API function: - - python XendClient.py fn args... - - The leading 'xend_' on the function can be omitted. - Example: - - > python XendClient.py domains - (domain 0 8) - > python XendClient.py domain 0 - (domain (id 0) (name Domain-0) (memory 128)) - """ - server = Xend() - fn = argv[1] - if not fn.startswith('xend'): - fn = 'xend_' + fn - args = argv[2:] - val = getattr(server, fn)(*args) - PrettyPrint.prettyprint(val) - print - -if __name__ == "__main__": - main(sys.argv) -else: - server = Xend() diff --git a/tools/xen/lib/xend/XendConsole.py b/tools/xen/lib/xend/XendConsole.py deleted file mode 100644 index 4420c388f2..0000000000 --- a/tools/xen/lib/xend/XendConsole.py +++ /dev/null @@ -1,179 +0,0 @@ -# Copyright (C) 2004 Mike Wray - -import socket -import xen.ext.xc -xc = xen.ext.xc.new() - -import sxp -import XendRoot -xroot = XendRoot.instance() -import XendDB - -import EventServer -eserver = EventServer.instance() - -from xen.xend.server import SrvDaemon -daemon = SrvDaemon.instance() - -class XendConsoleInfo: - """Console information record. - """ - - def __init__(self, console, dom1, port1, dom2, port2, conn=None): - self.console = console - self.dom1 = int(dom1) - self.port1 = int(port1) - self.dom2 = int(dom2) - self.port2 = int(port2) - self.conn = conn - #self.id = "%d.%d-%d.%d" % (self.dom1, self.port1, self.dom2, self.port2) - self.id = str(port1) - - def __str__(self): - s = "console" - s += " id=%s" % self.id - s += " src=%d.%d" % (self.dom1, self.port1) - s += " dst=%d.%d" % (self.dom2, self.port2) - s += " port=%s" % self.console - if self.conn: - s += " conn=%s:%s" % (self.conn[0], self.conn[1]) - return s - - def sxpr(self): - sxpr = ['console', - ['id', self.id], - ['src', self.dom1, self.port1], - ['dst', self.dom2, self.port2], - ['port', self.console], - ] - if self.conn: - sxpr.append(['connected', self.conn[0], self.conn[1]]) - return sxpr - - def connection(self): - return self.conn - - def update(self, consinfo): - conn = sxp.child(consinfo, 'connected') - if conn: - self.conn = conn[1:] - else: - self.conn = None - - def uri(self): - """Get the uri to use to connect to the console. - This will be a telnet: uri. - - return uri - """ - host = socket.gethostname() - return "telnet://%s:%s" % (host, self.console) - -class XendConsole: - - dbpath = "console" - - def __init__(self): - self.db = XendDB.XendDB(self.dbpath) - self.console = {} - self.console_db = self.db.fetchall("") - if xroot.get_rebooted(): - print 'XendConsole> rebooted: removing all console info' - self.rm_all() - eserver.subscribe('xend.domain.died', self.onDomainDied) - eserver.subscribe('xend.domain.destroy', self.onDomainDied) - - def rm_all(self): - """Remove all console info. Used after reboot. - """ - for (k, v) in self.console_db.items(): - self._delete_console(k) - - def refresh(self): - consoles = daemon.consoles() - cons = {} - for consinfo in consoles: - id = str(sxp.child_value(consinfo, 'id')) - cons[id] = consinfo - if id not in self.console: - self._new_console(consinfo) - for c in self.console.values(): - consinfo = cons.get(c.id) - if consinfo: - c.update(consinfo) - else: - self._delete_console(c.id) - - def onDomainDied(self, event, val): - dom = int(val) - #print 'XendConsole>onDomainDied', 'event', event, "dom=", dom - for c in self.consoles(): - #print 'onDomainDied', "dom=", dom, "dom1=", c.dom1, "dom2=", c.dom2 - if (c.dom1 == dom) or (c.dom2 == dom): - 'XendConsole>onDomainDied', 'delete console dom=', dom - ctrl = daemon.get_domain_console(dom) - if ctrl: - ctrl.close() - self._delete_console(c.id) - - def sync(self): - self.db.saveall("", self.console_db) - - def sync_console(self, id): - self.db.save(id, self.console_db[id]) - - def _new_console(self, consinfo): - # todo: xen needs a call to get current domain id. - dom1 = 0 - port1 = sxp.child_value(consinfo, 'local_port') - dom2 = sxp.child_value(consinfo, 'domain') - port2 = sxp.child_value(consinfo, 'remote_port') - console = sxp.child_value(consinfo, 'console_port') - info = XendConsoleInfo(console, dom1, int(port1), int(dom2), int(port2)) - info.update(consinfo) - self._add_console(info.id, info) - return info - - def _add_console(self, id, info): - self.console[id] = info - self.console_db[id] = info.sxpr() - self.sync_console(id) - - def _delete_console(self, id): - if id in self.console: - del self.console[id] - if id in self.console_db: - del self.console_db[id] - self.db.delete(id) - - def console_ls(self): - self.refresh() - return self.console.keys() - - def consoles(self): - self.refresh() - return self.console.values() - - def console_create(self, dom): - consinfo = daemon.console_create(dom) - info = self._new_console(consinfo) - return info - - def console_get(self, id): - self.refresh() - return self.console.get(id) - - def console_delete(self, id): - self._delete_console(id) - - def console_disconnect(self, id): - id = int(id) - daemon.console_disconnect(id) - -def instance(): - global inst - try: - inst - except: - inst = XendConsole() - return inst diff --git a/tools/xen/lib/xend/XendDB.py b/tools/xen/lib/xend/XendDB.py deleted file mode 100644 index 6a27e65b58..0000000000 --- a/tools/xen/lib/xend/XendDB.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright (C) 2004 Mike Wray - -import os -import os.path -import errno -import dircache -import time - -import sxp -import XendRoot -xroot = XendRoot.instance() - -class XendDB: - """Persistence for Xend. Stores data in files and directories. - """ - - def __init__(self, path=None): - self.dbpath = xroot.get_dbroot() - if path: - self.dbpath = os.path.join(self.dbpath, path) - pass - - def filepath(self, path): - return os.path.join(self.dbpath, path) - - def fetch(self, path): - fpath = self.filepath(path) - return self.fetchfile(fpath) - - def fetchfile(self, fpath): - pin = sxp.Parser() - fin = file(fpath, "rb") - try: - while 1: - try: - buf = fin.read(1024) - except IOError, ex: - if ex.errno == errno.EINTR: - continue - else: - raise - pin.input(buf) - if buf == '': - pin.input_eof() - break - finally: - fin.close() - return pin.get_val() - - def save(self, path, sxpr): - fpath = self.filepath(path) - return self.savefile(fpath, sxpr) - - def savefile(self, fpath, sxpr): - fdir = os.path.dirname(fpath) - if not os.path.isdir(fdir): - os.makedirs(fdir) - fout = file(fpath, "wb+") - try: - t = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) - fout.write("# %s %s\n" % (fpath, t)) - sxp.show(sxpr, out=fout) - finally: - fout.close() - - def fetchall(self, path): - dpath = self.filepath(path) - d = {} - for k in dircache.listdir(dpath): - try: - v = self.fetchfile(os.path.join(dpath, k)) - d[k] = v - except: - pass - return d - - def saveall(self, path, d): - for (k, v) in d.items(): - self.save(os.path.join(path, k), v) - - def delete(self, path): - dpath = self.filepath(path) - os.unlink(dpath) - - def ls(self, path): - dpath = self.filepath(path) - return dircache.listdir(dpath) - - - - diff --git a/tools/xen/lib/xend/XendDomain.py b/tools/xen/lib/xend/XendDomain.py deleted file mode 100644 index 3aaf080c36..0000000000 --- a/tools/xen/lib/xend/XendDomain.py +++ /dev/null @@ -1,369 +0,0 @@ -# Copyright (C) 2004 Mike Wray - -"""Handler for domain operations. - Nothing here is persistent (across reboots). - Needs to be persistent for one uptime. -""" -import sys - -from twisted.internet import defer - -import xen.ext.xc; xc = xen.ext.xc.new() - -import sxp -import XendRoot -xroot = XendRoot.instance() -import XendDB -import XendDomainInfo -import XendConsole -import EventServer - -from xen.xend.server import SrvDaemon -xend = SrvDaemon.instance() - -eserver = EventServer.instance() - -__all__ = [ "XendDomain" ] - -class XendDomain: - """Index of all domains. Singleton. - """ - - dbpath = "domain" - domain = {} - - def __init__(self): - self.xconsole = XendConsole.instance() - # Table of domain info indexed by domain id. - self.db = XendDB.XendDB(self.dbpath) - #self.domain = {} - self.domain_db = self.db.fetchall("") - if xroot.get_rebooted(): - print 'XendDomain> rebooted: removing all domain info' - self.rm_all() - eserver.subscribe('xend.virq', self.onVirq) - self.initial_refresh() - - def onVirq(self, event, val): - print 'XendDomain> virq', val - self.reap() - - def rm_all(self): - """Remove all domain info. Used after reboot. - """ - for (k, v) in self.domain_db.items(): - self._delete_domain(k, notify=0) - - def initial_refresh(self): - """Refresh initial domain info from domain_db. - """ - print "initial_refresh>" - for d in self.domain_db.values(): print 'db dom=', d - domlist = xc.domain_getinfo() - for d in domlist: print 'xc dom=', d - doms = {} - for d in domlist: - domid = str(d['dom']) - doms[domid] = d - dlist = [] - for config in self.domain_db.values(): - domid = str(sxp.child_value(config, 'id')) - print "dom=", domid, "config=", config - if domid in doms: - print "dom=", domid, "new" - deferred = self._new_domain(config, doms[domid]) - dlist.append(deferred) - else: - print "dom=", domid, "del" - self._delete_domain(domid) - deferred = defer.DeferredList(dlist, fireOnOneErrback=1) - def cbok(val): - #print "doms:" - #for d in self.domain.values(): print 'dom', d - self.refresh() - print "XendDomain>initial_refresh> doms:" - for d in self.domain.values(): print 'dom', d - deferred.addCallback(cbok) - - def sync(self): - """Sync domain db to disk. - """ - self.db.saveall("", self.domain_db) - - def sync_domain(self, dom): - """Sync info for a domain to disk. - - dom domain id (string) - """ - self.db.save(dom, self.domain_db[dom]) - - def close(self): - pass - - def _new_domain(self, savedinfo, info): - """Create a domain entry from saved info. - """ -## console = None -## kernel = None -## id = sxp.child_value(info, 'id') -## dom = int(id) -## name = sxp.child_value(info, 'name') -## memory = int(sxp.child_value(info, 'memory')) -## consoleinfo = sxp.child(info, 'console') -## if consoleinfo: -## consoleid = sxp.child_value(consoleinfo, 'id') -## console = self.xconsole.console_get(consoleid) -## if dom and console is None: -## # Try to connect a console. -## console = self.xconsole.console_create(dom) -## config = sxp.child(info, 'config') -## if config: -## image = sxp.child(info, 'image') -## if image: -## image = sxp.child0(image) -## kernel = sxp.child_value(image, 'kernel') -## dominfo = XendDomainInfo.XendDomainInfo( -## config, dom, name, memory, kernel, console) - config = sxp.child_value(savedinfo, 'config') - deferred = XendDomainInfo.vm_recreate(config, info) - def fn(dominfo): - self.domain[dominfo.id] = dominfo - deferred.addCallback(fn) - return deferred - - def _add_domain(self, id, info, notify=1): - self.domain[id] = info - self.domain_db[id] = info.sxpr() - self.sync_domain(id) - if notify: eserver.inject('xend.domain.created', id) - - def _delete_domain(self, id, notify=1): - if id in self.domain: - if notify: eserver.inject('xend.domain.died', id) - del self.domain[id] - if id in self.domain_db: - del self.domain_db[id] - self.db.delete(id) - - def reap(self): - """Go through the domains looking for ones that have crashed or stopped. - Tidy them up. - """ - print 'XendDomain>reap>' - domlist = xc.domain_getinfo() - casualties = [] - for d in domlist: - #print 'dom', d - dead = 0 - dead = dead or (d['crashed'] or d['shutdown']) - dead = dead or (d['dying'] and - not(d['running'] or d['paused'] or d['blocked'])) - if dead: - casualties.append(d) - for d in casualties: - id = str(d['dom']) - print 'XendDomain>reap> died id=', id, d - dominfo = self.domain.get(id) - if not dominfo: continue - dominfo.died() - self.domain_destroy(id, refresh=0) - print 'XendDomain>reap<' - - def refresh(self): - """Refresh domain list from Xen. - """ - domlist = xc.domain_getinfo() - # Index the domlist by id. - # Add entries for any domains we don't know about. - doms = {} - for d in domlist: - id = str(d['dom']) - doms[id] = d - if id not in self.domain: - config = None - #image = None - #newinfo = XendDomainInfo.XendDomainInfo( - # config, d['dom'], d['name'], d['mem_kb']/1024, image=image, info=d) - deferred = XendDomainInfo.vm_recreate(config, d) - def fn(dominfo): - self._add_domain(dominfo.id, dominfo) - deferred.addCallback(fn) - # Remove entries for domains that no longer exist. - for d in self.domain.values(): - dominfo = doms.get(d.id) - if dominfo: - d.update(dominfo) - else: - self._delete_domain(d.id) - self.reap() - - def refresh_domain(self, id): - dom = int(id) - dominfo = xc.domain_getinfo(dom, 1) - if dominfo == [] or dominfo[0]['dom'] != dom: - try: - self._delete_domain(id) - except: - print 'refresh_domain: error' - raise - pass - else: - d = self.domain.get(id) - if d: - d.update(dominfo[0]) - - def domain_ls(self): - # List domains. - # Update info from kernel first. - self.refresh() - return self.domain.keys() - - def domains(self): - self.refresh() - return self.domain.values() - - def domain_create(self, config): - # Create domain, log it. - deferred = XendDomainInfo.vm_create(config) - def fn(dominfo): - self._add_domain(dominfo.id, dominfo) - return dominfo - deferred.addCallback(fn) - return deferred - - def domain_get(self, id): - id = str(id) - self.refresh_domain(id) - return self.domain.get(id) - - def domain_unpause(self, id): - """(Re)start domain running. - """ - dom = int(id) - eserver.inject('xend.domain.unpause', id) - return xc.domain_unpause(dom=dom) - - def domain_pause(self, id): - """Pause domain execution. - """ - dom = int(id) - eserver.inject('xend.domain.pause', id) - return xc.domain_pause(dom=dom) - - def domain_shutdown(self, id, reason='poweroff'): - """Shutdown domain (nicely). - """ - dom = int(id) - if dom <= 0: - return 0 - eserver.inject('xend.domain.shutdown', [id, reason]) - val = xend.domain_shutdown(dom, reason) - self.refresh() - return val - - def domain_destroy(self, id, refresh=1): - """Terminate domain immediately. - """ - dom = int(id) - if dom <= 0: - return 0 - eserver.inject('xend.domain.destroy', id) - val = xc.domain_destroy(dom=dom) - if refresh: self.refresh() - return val - - def domain_migrate(self, id, dst): - """Start domain migration. - """ - # Need a cancel too? - pass - - def domain_save(self, id, dst, progress=0): - """Save domain state to file, destroy domain. - """ - dom = int(id) - dominfo = self.domain_get(id) - if not dominfo: - return -1 - vmconfig = sxp.to_string(dominfo.sxpr()) - self.domain_pause(id) - eserver.inject('xend.domain.save', id) - rc = xc.linux_save(dom=dom, state_file=dst, vmconfig=vmconfig, progress=progress) - if rc == 0: - self.domain_destroy(id) - return rc - - def domain_restore(self, src, progress=0): - """Restore domain from file. - """ - dominfo = XendDomainInfo.vm_restore(src, progress=progress) - self._add_domain(dominfo.id, dominfo) - return dominfo - - #============================================================================ - # Backward compatibility stuff from here on. - - def domain_pincpu(self, dom, cpu): - dom = int(dom) - return xc.domain_pincpu(dom, cpu) - - def domain_cpu_bvt_set(self, dom, mcuadv, warp, warpl, warpu): - dom = int(dom) - return xc.bvtsched_domain_set(dom=dom, mcuadv=mcuadv, - warp=warp, warpl=warpl, warpu=warpu) - - def domain_cpu_bvt_get(self, dom): - dom = int(dom) - return xc.bvtsched_domain_get(dom) - - def domain_cpu_atropos_set(self, dom, period, slice, latency, xtratime): - dom = int(dom) - return xc.atropos_domain_set(dom, period, slice, latency, xtratime) - - def domain_cpu_atropos_get(self, dom): - dom = int(dom) - return xc.atropos_domain_get(dom) - - def domain_vif_ls(self, dom): - dominfo = self.domain_get(dom) - if not dominfo: return None - devs = dominfo.get_devices('vif') - return range(0, len(devs)) - - def domain_vif_get(self, dom, vif): - dominfo = self.domain_get(dom) - if not dominfo: return None - return dominfo.get_device_by_index(vif) - -## def domain_vif_ip_add(self, dom, vif, ip): -## dom = int(dom) -## return xenctl.ip.setup_vfr_rules_for_vif(dom, vif, ip) - - def domain_vbd_ls(self, dom): - dominfo = self.domain_get(dom) - if not dominfo: return [] - devs = dominfo.get_devices('vbd') - return [ sxp.child_value(v, 'dev') for v in devs ] - - def domain_vbd_get(self, dom, vbd): - dominfo = self.domain_get(dom) - if not dominfo: return None - devs = dominfo.get_devices('vbd') - for v in devs: - if sxp.child_value(v, 'dev') == vbd: - return v - return None - - def domain_shadow_control(self, dom, op): - dom = int(dom) - return xc.shadow_control(dom, op) - - #============================================================================ - -def instance(): - global inst - try: - inst - except: - inst = XendDomain() - return inst diff --git a/tools/xen/lib/xend/XendDomainConfig.py b/tools/xen/lib/xend/XendDomainConfig.py deleted file mode 100644 index 35db31ff51..0000000000 --- a/tools/xen/lib/xend/XendDomainConfig.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright (C) 2004 Mike Wray - -"""Handler for persistent domain configs. - -""" - -import sxp -import XendDB -import XendDomain - -__all__ = [ "XendDomainConfig" ] - -class XendDomainConfig: - - dbpath = 'config' - - def __init__(self): - self.db = XendDB.XendDB(self.dbpath) - - def domain_config_ls(self, path): - return self.db.ls(path) - - def domain_config_create(self, path, sxpr): - self.db.save(path, sxpr) - pass - - def domain_config_delete(self, path): - self.db.delete(path) - - def domain_config_instance(self, path): - """Create a domain from a config. - """ - config = self.db.fetch(path) - xd = XendDomain.instance() - newdom = xd.domain_create(config) - return newdom - -def instance(): - global inst - try: - inst - except: - inst = XendDomainConfig() - return inst diff --git a/tools/xen/lib/xend/XendDomainInfo.py b/tools/xen/lib/xend/XendDomainInfo.py deleted file mode 100644 index a7e5aa3b2f..0000000000 --- a/tools/xen/lib/xend/XendDomainInfo.py +++ /dev/null @@ -1,908 +0,0 @@ -#!/usr/bin/python -# Copyright (C) 2004 Mike Wray - -"""Representation of a single domain. -Includes support for domain construction, using -open-ended configurations. - -Author: Mike Wray - -""" - -import string -import re -import sys -import os - -from twisted.internet import defer - -import xen.ext.xc; xc = xen.ext.xc.new() -import xen.util.ip - -import sxp - -import XendConsole -xendConsole = XendConsole.instance() - -import server.SrvDaemon -xend = server.SrvDaemon.instance() - -SIF_BLK_BE_DOMAIN = (1<<4) -SIF_NET_BE_DOMAIN = (1<<5) - -def readlines(fd): - """Version of readlines safe against EINTR. - """ - import errno - - lines = [] - while 1: - try: - line = fd.readline() - except IOError, ex: - if ex.errno == errno.EINTR: - continue - else: - raise - if line == '': break - lines.append(line) - return lines - -class VmError(ValueError): - """Vm construction error.""" - - def __init__(self, value): - self.value = value - - def __str__(self): - return self.value - - -def blkdev_name_to_number(name): - """Take the given textual block-device name (e.g., '/dev/sda1', - 'hda') and return the device number used by the OS. """ - - if not re.match( '/dev/', name ): - name = '/dev/' + name - - return os.stat(name).st_rdev - -def lookup_raw_partn(partition): - """Take the given block-device name (e.g., '/dev/sda1', 'hda') - and return a dictionary { device, start_sector, - nr_sectors, type } - device: Device number of the given partition - start_sector: Index of first sector of the partition - nr_sectors: Number of sectors comprising this partition - type: 'Disk' or identifying name for partition type - """ - - if not re.match( '/dev/', partition ): - partition = '/dev/' + partition - - drive = re.split( '[0-9]', partition )[0] - - if drive == partition: - fd = os.popen( '/sbin/sfdisk -s ' + drive + ' 2>/dev/null' ) - line = readline(fd) - if line: - return [ { 'device' : blkdev_name_to_number(drive), - 'start_sector' : long(0), - 'nr_sectors' : long(line) * 2, - 'type' : 'Disk' } ] - return None - - # determine position on disk - fd = os.popen( '/sbin/sfdisk -d ' + drive + ' 2>/dev/null' ) - - #['/dev/sda3 : start= 16948575, size=16836120, Id=83, bootable\012'] - lines = readlines(fd) - for line in lines: - m = re.search( '^' + partition + '\s*: start=\s*([0-9]+), ' + - 'size=\s*([0-9]+), Id=\s*(\S+).*$', line) - if m: - return [ { 'device' : blkdev_name_to_number(drive), - 'start_sector' : long(m.group(1)), - 'nr_sectors' : long(m.group(2)), - 'type' : m.group(3) } ] - - return None - -def lookup_disk_uname(uname): - """Lookup a list of segments for a physical device. - uname [string]: name of the device in the format \'phy:dev\' for a physical device - returns [list of dicts]: list of extents that make up the named device - """ - ( type, d_name ) = string.split( uname, ':' ) - - if type == "phy": - segments = lookup_raw_partn( d_name ) - else: - segments = None - return segments - -def make_disk(dom, uname, dev, mode, recreate=0): - """Create a virtual disk device for a domain. - - @returns Deferred - """ - segments = lookup_disk_uname(uname) - if not segments: - raise VmError("vbd: Segments not found: uname=%s" % uname) - if len(segments) > 1: - raise VmError("vbd: Multi-segment vdisk: uname=%s" % uname) - segment = segments[0] - vdev = blkdev_name_to_number(dev) - ctrl = xend.blkif_create(dom, recreate=recreate) - - def fn(ctrl): - return xend.blkif_dev_create(dom, vdev, mode, segment, recreate=recreate) - ctrl.addCallback(fn) - return ctrl - -def make_vif(dom, vif, vmac, recreate=0): - """Create a virtual network device for a domain. - - - @returns Deferred - """ - xend.netif_create(dom, recreate=recreate) - d = xend.netif_dev_create(dom, vif, vmac, recreate=recreate) - return d - -def vif_up(iplist): - """send an unsolicited ARP reply for all non link-local IP addresses. - - iplist IP addresses - """ - - IP_NONLOCAL_BIND = '/proc/sys/net/ipv4/ip_nonlocal_bind' - - def get_ip_nonlocal_bind(): - return int(open(IP_NONLOCAL_BIND, 'r').read()[0]) - - def set_ip_nonlocal_bind(v): - print >> open(IP_NONLOCAL_BIND, 'w'), str(v) - - def link_local(ip): - return xen.util.ip.check_subnet(ip, '169.254.0.0', '255.255.0.0') - - def arping(ip, gw): - cmd = '/usr/sbin/arping -A -b -I eth0 -c 1 -s %s %s' % (ip, gw) - print cmd - os.system(cmd) - - gateway = xen.util.ip.get_current_ipgw() or '255.255.255.255' - nlb = get_ip_nonlocal_bind() - if not nlb: set_ip_nonlocal_bind(1) - try: - for ip in iplist: - if not link_local(ip): - arping(ip, gateway) - finally: - if not nlb: set_ip_nonlocal_bind(0) - -config_handlers = {} - -def add_config_handler(name, h): - """Add a handler for a config field. - - name field name - h handler: fn(vm, config, field, index) - """ - config_handlers[name] = h - -def get_config_handler(name): - """Get a handler for a config field. - - returns handler or None - """ - return config_handlers.get(name) - -"""Table of handlers for virtual machine images. -Indexed by image type. -""" -image_handlers = {} - -def add_image_handler(name, h): - """Add a handler for an image type - name image type - h handler: fn(config, name, memory, image) - """ - image_handlers[name] = h - -def get_image_handler(name): - """Get the handler for an image type. - name image type - - returns handler or None - """ - return image_handlers.get(name) - -"""Table of handlers for devices. -Indexed by device type. -""" -device_handlers = {} - -def add_device_handler(name, h): - """Add a handler for a device type. - - name device type - h handler: fn(vm, dev) - """ - device_handlers[name] = h - -def get_device_handler(name): - """Get the handler for a device type. - - name device type - - returns handler or None - """ - return device_handlers.get(name) - -def vm_create(config): - """Create a VM from a configuration. - If a vm has been partially created and there is an error it - is destroyed. - - config configuration - - returns Deferred - raises VmError for invalid configuration - """ - print 'vm_create>' - vm = XendDomainInfo() - return vm.construct(config) - -def vm_recreate(config, info): - """Create the VM object for an existing domain. - """ - vm = XendDomainInfo() - vm.recreate = 1 - vm.setdom(info['dom']) - vm.name = info['name'] - vm.memory = info['mem_kb']/1024 - if config: - d = vm.construct(config) - else: - d = defer.Deferred() - d.callback(vm) - return d - -def vm_restore(src, progress=0): - """Restore a VM from a disk image. - - src saved state to restore - progress progress reporting flag - returns deferred - raises VmError for invalid configuration - """ - vm = XendDomainInfo() - ostype = "linux" #todo Set from somewhere (store in the src?). - restorefn = getattr(xc, "%s_restore" % ostype) - d = restorefn(state_file=src, progress=progress) - dom = int(d['dom']) - if dom < 0: - raise VMError('restore failed') - vmconfig = sxp.from_string(d['vmconfig']) - vm.config = sxp.child_value(vmconfig, 'config') - deferred = vm.dom_configure(dom) - def vifs_cb(val, vm): - vif_up(vm.ipaddrs) - deferred.addCallback(vifs_cb, vm) - return deferred - -def dom_get(dom): - domlist = xc.domain_getinfo(dom=dom) - if domlist and dom == domlist[0]['dom']: - return domlist[0] - return None - - -def append_deferred(dlist, v): - if isinstance(v, defer.Deferred): - dlist.append(v) - -def _vm_configure1(val, vm): - d = vm.create_devices() - print '_vm_configure1> made devices...' - def cbok(x): - print '_vm_configure1> cbok', x - return x - d.addCallback(cbok) - d.addCallback(_vm_configure2, vm) - print '_vm_configure1<' - return d - -def _vm_configure2(val, vm): - print '>callback _vm_configure2...' - d = vm.configure_fields() - def cbok(results): - print '_vm_configure2> cbok', results - return vm - def cberr(err): - print '_vm_configure2> cberr', err - vm.destroy() - return err - d.addCallback(cbok) - d.addErrback(cberr) - print '<_vm_configure2' - return d - -class XendDomainInfo: - """Virtual machine object.""" - - def __init__(self): - self.recreate = 0 - self.config = None - self.id = None - self.dom = None - self.name = None - self.memory = None - self.image = None - self.ramdisk = None - self.cmdline = None - self.console = None - self.devices = {} - self.configs = [] - self.info = None - self.ipaddrs = [] - self.blkif_backend = 0 - self.netif_backend = 0 - #todo: state: running, suspended - self.state = 'running' - #todo: set to migrate info if migrating - self.migrate = None - - def setdom(self, dom): - self.dom = int(dom) - self.id = str(dom) - - def update(self, info): - """Update with info from xc.domain_getinfo(). - """ - self.info = info - self.memory = self.info['mem_kb'] / 1024 - - def __str__(self): - s = "domain" - s += " id=" + self.id - s += " name=" + self.name - s += " memory=" + str(self.memory) - if self.console: - s += " console=" + self.console.id - if self.image: - s += " image=" + self.image - s += "" - return s - - __repr__ = __str__ - - def sxpr(self): - sxpr = ['domain', - ['id', self.id], - ['name', self.name], - ['memory', self.memory] ] - if self.info: - run = (self.info['running'] and 'r') or '-' - block = (self.info['blocked'] and 'b') or '-' - stop = (self.info['paused'] and 'p') or '-' - susp = (self.info['shutdown'] and 's') or '-' - crash = (self.info['crashed'] and 'c') or '-' - state = run + block + stop + susp + crash - sxpr.append(['state', state]) - if self.info['shutdown']: - reasons = ["poweroff", "reboot", "suspend"] - reason = reasons[self.info['shutdown_reason']] - sxpr.append(['shutdown_reason', reason]) - sxpr.append(['cpu', self.info['cpu']]) - sxpr.append(['cpu_time', self.info['cpu_time']/1e9]) - if self.console: - sxpr.append(self.console.sxpr()) - if self.config: - sxpr.append(['config', self.config]) - return sxpr - - def construct(self, config): - # todo - add support for scheduling params? - self.config = config - try: - self.name = sxp.child_value(config, 'name') - self.memory = int(sxp.child_value(config, 'memory', '128')) - self.configure_backends() - image = sxp.child_value(config, 'image') - image_name = sxp.name(image) - image_handler = get_image_handler(image_name) - if image_handler is None: - raise VmError('unknown image type: ' + image_name) - image_handler(self, image) - deferred = self.configure() - except StandardError, ex: - # Catch errors, cleanup and re-raise. - self.destroy() - raise - def cbok(x): - print 'vm_create> cbok', x - return x - deferred.addCallback(cbok) - print 'vm_create<' - return deferred - - def config_devices(self, name): - """Get a list of the 'device' nodes of a given type from the config. - - name device type - return list of device configs - """ - devices = [] - for d in sxp.children(self.config, 'device'): - dev = sxp.child0(d) - if dev is None: continue - if name == sxp.name(dev): - devices.append(dev) - return devices - - def add_device(self, type, dev): - """Add a device to a virtual machine. - - dev device to add - """ - dl = self.devices.get(type, []) - dl.append(dev) - self.devices[type] = dl - - def get_devices(self, type): - val = self.devices.get(type, []) - return val - - def get_device_by_id(self, type, id): - """Get the device with the given id. - - id device id - - returns device or None - """ - dl = self.get_devices(type) - for d in dl: - if d.getprop('id') == id: - return d - return None - - def get_device_by_index(self, type, idx): - """Get the device with the given index. - - idx device index - - returns device or None - """ - dl = self.get_devices(type) - if 0 <= idx < len(dl): - return dl[idx] - else: - return None - - def add_config(self, val): - """Add configuration data to a virtual machine. - - val data to add - """ - self.configs.append(val) - - def destroy(self): - if self.dom <= 0: - return 0 - return xc.domain_destroy(dom=self.dom) - - def died(self): - print 'died>', self.dom - self.release_devices() - - def release_devices(self): - print 'release_devices>', self.dom - self.release_vifs() - self.release_vbds() - self.devices = {} - - def release_vifs(self): - print 'release_vifs>', self.dom - if self.dom is None: return - ctrl = xend.netif_get(self.dom) - if ctrl: - ctrl.destroy() - - def release_vbds(self): - print 'release_vbds>', self.dom - if self.dom is None: return - ctrl = xend.blkif_get(self.dom) - if ctrl: - ctrl.destroy() - - def show(self): - """Print virtual machine info. - """ - print "[VM dom=%d name=%s memory=%d" % (self.dom, self.name, self.memory) - print "image:" - sxp.show(self.image) - print - for dl in self.devices: - for dev in dl: - print "device:" - sxp.show(dev) - print - for val in self.configs: - print "config:" - sxp.show(val) - print - print "]" - - def init_domain(self): - """Initialize the domain memory. - """ - if self.recreate: return - memory = self.memory - name = self.name - cpu = int(sxp.child_value(self.config, 'cpu', '-1')) - print 'init_domain>', memory, name, cpu - dom = xc.domain_create(mem_kb= memory * 1024, name= name, cpu= cpu) - if dom <= 0: - raise VmError('Creating domain failed: name=%s memory=%d' - % (name, memory)) - self.setdom(dom) - - def build_domain(self, ostype, kernel, ramdisk, cmdline, vifs_n): - """Build the domain boot image. - """ - if self.recreate: return - if len(cmdline) >= 256: - print 'Warning: kernel cmdline too long' - dom = self.dom - buildfn = getattr(xc, '%s_build' % ostype) - print 'build_domain>', ostype, dom, kernel, cmdline, ramdisk - flags = 0 - if self.netif_backend: flags |= SIF_NET_BE_DOMAIN - if self.blkif_backend: flags |= SIF_BLK_BE_DOMAIN - err = buildfn(dom = dom, - image = kernel, - control_evtchn = self.console.port2, - cmdline = cmdline, - ramdisk = ramdisk, - flags = flags) - if err != 0: - raise VmError('Building domain failed: type=%s dom=%d err=%d' - % (ostype, dom, err)) - - def create_domain(self, ostype, kernel, ramdisk, cmdline, vifs_n): - """Create a domain. Builds the image but does not configure it. - - ostype OS type - kernel kernel image - ramdisk kernel ramdisk - cmdline kernel commandline - vifs_n number of network interfaces - """ - print 'create_domain>', ostype, kernel - if not self.recreate: - if not os.path.isfile(kernel): - raise VmError('Kernel image does not exist: %s' % kernel) - if ramdisk and not os.path.isfile(ramdisk): - raise VMError('Kernel ramdisk does not exist: %s' % ramdisk) - print 'create-domain> init_domain...' - self.init_domain() - print 'create_domain>', 'dom=', self.dom - self.console = xendConsole.console_create(self.dom) - self.build_domain(ostype, kernel, ramdisk, cmdline, vifs_n) - self.image = kernel - self.ramdisk = ramdisk - self.cmdline = cmdline - - def create_devices(self): - """Create the devices for a vm. - - returns Deferred - raises VmError for invalid devices - """ - print '>create_devices' - dlist = [] - devices = sxp.children(self.config, 'device') - index = {} - for d in devices: - dev = sxp.child0(d) - if dev is None: - raise VmError('invalid device') - dev_name = sxp.name(dev) - dev_index = index.get(dev_name, 0) - dev_handler = get_device_handler(dev_name) - if dev_handler is None: - raise VmError('unknown device type: ' + dev_name) - v = dev_handler(self, dev, dev_index) - append_deferred(dlist, v) - index[dev_name] = dev_index + 1 - deferred = defer.DeferredList(dlist, fireOnOneErrback=1) - print ' created', dev - return id - defer.addCallback(fn) - return defer - -def vm_dev_vbd(vm, val, index): - """Create a virtual block device (vbd). - - vm virtual machine - val vbd config - index vbd index - """ - if vm.blkif_backend: - raise VmError('vbd: vbd in blkif backend domain') - vdev = index - uname = sxp.child_value(val, 'uname') - if not uname: - raise VMError('vbd: Missing uname') - dev = sxp.child_value(val, 'dev') - if not dev: - raise VMError('vbd: Missing dev') - mode = sxp.child_value(val, 'mode', 'r') - defer = make_disk(vm.dom, uname, dev, mode, vm.recreate) - def fn(vbd): - dev = xend.blkif_dev(vm.dom, vdev) - vm.add_device('vbd', dev) - return vbd - defer.addCallback(fn) - return defer - -def parse_pci(val): - if isinstance(val, StringType): - radix = 10 - if val.startswith('0x') or val.startswith('0X'): - radix = 16 - v = int(val, radix) - else: - v = val - return v - -def vm_dev_pci(vm, val, index): - bus = sxp.child_value(val, 'bus') - if not bus: - raise VMError('pci: Missing bus') - dev = sxp.child_value(val, 'dev') - if not dev: - raise VMError('pci: Missing dev') - func = sxp.child_value(val, 'func') - if not func: - raise VMError('pci: Missing func') - try: - bus = parse_pci(bus) - dev = parse_pci(dev) - func = parse_pci(func) - except: - raise VMError('pci: invalid parameter') - rc = xc.physdev_pci_access_modify(dom=vm.dom, bus=bus, dev=dev, - func=func, enable=1) - if rc < 0: - #todo non-fatal - raise VMError('pci: Failed to configure device: bus=%s dev=%s func=%s' % - (bus, dev, func)) - return rc - - -def vm_field_vfr(vm, config, val, index): - """Handle a vfr field in a config. - - vm virtual machine - config vm config - val vfr field - """ - # Get the rules and add them. - # (vfr (vif (id foo) (ip x.x.x.x)) ... ) - list = sxp.children(val, 'vif') - ipaddrs = [] - for v in list: - id = sxp.child_value(v, 'id') - if id is None: - raise VmError('vfr: missing vif id') - id = int(id) - dev = vm.get_device_by_index('vif', id) - if not dev: - raise VmError('vfr: invalid vif id %d' % id) - vif = sxp.child_value(dev, 'vif') - ip = sxp.child_value(v, 'ip') - if not ip: - raise VmError('vfr: missing ip address') - ipaddrs.append(ip); - # todo: Configure the ipaddrs. - vm.ipaddrs = ipaddrs - -def vnet_bridge(vnet, vmac, dom, idx): - """Add the device for the vif to the bridge for its vnet. - """ - vif = "vif%d.%d" % (dom, idx) - try: - cmd = "(vif.conn (vif %s) (vnet %s) (vmac %s))" % (vif, vnet, vmac) - print "*** vnet_bridge>", cmd - out = file("/proc/vnet/policy", "wb") - out.write(cmd) - err = out.close() - print "vnet_bridge>", "err=", err - except IOError, ex: - print "vnet_bridge>", ex - -def vm_field_vnet(vm, config, val, index): - """Handle a vnet field in a config. - - vm virtual machine - config vm config - val vnet field - index index - """ - # Get the vif children. For each vif look up the vif device - # with the given id and configure its vnet. - # (vnet (vif (id foo) (vnet 2) (mac x:x:x:x:x:x)) ... ) - vif_vnets = sxp.children(val, 'vif') - for v in vif_vnets: - id = sxp.child_value(v, 'id') - if id is None: - raise VmError('vnet: missing vif id') - dev = vm.get_device_by_id('vif', id) - #vnet = sxp.child_value(v, 'vnet', 1) - #mac = sxp.child_value(dev, 'mac') - #vif = sxp.child_value(dev, 'vif') - #vnet_bridge(vnet, mac, vm.dom, 0) - #vm.add_config([ 'vif.vnet', ['id', id], ['vnet', vnet], ['mac', mac]]) - -# Register image handlers for linux and bsd. -add_image_handler('linux', vm_image_linux) -add_image_handler('netbsd', vm_image_netbsd) - -# Register device handlers for vifs and vbds. -add_device_handler('vif', vm_dev_vif) -add_device_handler('vbd', vm_dev_vbd) -add_device_handler('pci', vm_dev_pci) - -# Register config handlers for vfr and vnet. -add_config_handler('vfr', vm_field_vfr) -add_config_handler('vnet', vm_field_vnet) diff --git a/tools/xen/lib/xend/XendMigrate.py b/tools/xen/lib/xend/XendMigrate.py deleted file mode 100644 index 1580ba83ed..0000000000 --- a/tools/xen/lib/xend/XendMigrate.py +++ /dev/null @@ -1,103 +0,0 @@ -# Copyright (C) 2004 Mike Wray - -import sys -import socket - -import sxp -import XendDB -import EventServer; eserver = EventServer.instance() - -class XendMigrateInfo: - - # states: begin, active, failed, succeeded? - - def __init__(self, id, dom, dst): - self.id = id - self.state = 'begin' - self.src_host = socket.gethostname() - self.src_dom = dom - self.dst_host = dst - self.dst_dom = None - - def set_state(self, state): - self.state = state - - def get_state(self): - return self.state - - def sxpr(self): - sxpr = ['migrate', ['id', self.id], ['state', self.state] ] - sxpr_src = ['src', ['host', self.src_host], ['domain', self.src_dom] ] - sxpr.append(sxpr_src) - sxpr_dst = ['dst', ['host', self.dst] ] - if self.dst_dom: - sxpr_dst.append(['domain', self.dst_dom]) - sxpr.append(sxpr_dst) - return sxpr - - -class XendMigrate: - # Represents migration in progress. - # Use log for indications of begin/end/errors? - # Need logging of: domain create/halt, migrate begin/end/fail - # Log via event server? - - dbpath = "migrate" - - def __init__(self): - self.db = XendDB.XendDB(self.dbpath) - self.migrate = {} - self.migrate_db = self.db.fetchall("") - self.id = 0 - - def nextid(self): - self.id += 1 - return "%d" % self.id - - def sync(self): - self.db.saveall("", self.migrate_db) - - def sync_migrate(self, id): - self.db.save(id, self.migrate_db[id]) - - def close(self): - pass - - def _add_migrate(self, id, info): - self.migrate[id] = info - self.migrate_db[id] = info.sxpr() - self.sync_migrate(id) - #eserver.inject('xend.migrate.begin', info.sxpr()) - - def _delete_migrate(self, id): - #eserver.inject('xend.migrate.end', id) - del self.migrate[id] - del self.migrate_db[id] - self.db.delete(id) - - def migrate_ls(self): - return self.migrate.keys() - - def migrates(self): - return self.migrate.values() - - def migrate_get(self, id): - return self.migrate.get(id) - - def migrate_begin(self, dom, dst): - # Check dom for existence, not migrating already. - # Create migrate info, tell xend to migrate it? - # - or fork migrate command ourselves? - # Subscribe to migrate notifications (for updating). - id = self.nextid() - info = XenMigrateInfo(id, dom, dst) - self._add_migrate(id, info) - return id - -def instance(): - global inst - try: - inst - except: - inst = XendMigrate() - return inst diff --git a/tools/xen/lib/xend/XendNode.py b/tools/xen/lib/xend/XendNode.py deleted file mode 100644 index 7221785aff..0000000000 --- a/tools/xen/lib/xend/XendNode.py +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright (C) 2004 Mike Wray - -"""Handler for node operations. - Has some persistent state: - - logs - - notification urls - -""" - -import os -import xen.ext.xc - -class XendNode: - - def __init__(self): - self.xc = xen.ext.xc.new() - - def shutdown(self): - return 0 - - def reboot(self): - return 0 - - def notify(self, uri): - return 0 - - def cpu_bvt_slice_set(self, slice): - ret = 0 - #ret = self.xc.bvtsched_global_set(ctx_allow=slice) - return ret - - def cpu_bvt_slice_get(self, slice): - ret = 0 - #ret = self.xc.bvtsched_global_get() - return ret - - def cpu_rrobin_slice_set(self, slice): - ret = 0 - #ret = self.xc.rrobin_global_set(slice) - return ret - - def info(self): - return self.nodeinfo() + self.physinfo() - - def nodeinfo(self): - (sys, host, rel, ver, mch) = os.uname() - return [['system', sys], - ['host', host], - ['release', rel], - ['version', ver], - ['machine', mch]] - - def physinfo(self): - pinfo = self.xc.physinfo() - info = [['cores', pinfo['cores']], - ['hyperthreads_per_core', pinfo['ht_per_core']], - ['cpu_mhz', pinfo['cpu_khz']/1000], - ['memory', pinfo['total_pages']/256], - ['free_memory', pinfo['free_pages']/256]] - return info - - - -def instance(): - global inst - try: - inst - except: - inst = XendNode() - return inst - diff --git a/tools/xen/lib/xend/XendRoot.py b/tools/xen/lib/xend/XendRoot.py deleted file mode 100644 index 665f5df29e..0000000000 --- a/tools/xen/lib/xend/XendRoot.py +++ /dev/null @@ -1,156 +0,0 @@ -# Copyright (C) 2004 Mike Wray - -"""Xend root class. -Creates the event server and handles configuration. -""" - -import os -import os.path -import sys -import EventServer - -# Initial create of the event server. -eserver = EventServer.instance() - -import sxp - -def reboots(): - """Get a list of system reboots from wtmp. - """ - out = os.popen('/usr/bin/last reboot', 'r') - list = [ x.strip() for x in out if x.startswith('reboot') ] - return list - -def last_reboot(): - """Get the last known system reboot. - """ - l = reboots() - return (l and l[-1]) or None - -class XendRoot: - """Root of the management classes.""" - - lastboot_default = "/var/xen/lastboot" - - """Default path to the root of the database.""" - dbroot_default = "/var/xen/xend-db" - - """Default path to the config file.""" - config_default = "/etc/xen/xend-config.sxp" - - """Environment variable used to override config_default.""" - config_var = "XEND_CONFIG" - - def __init__(self): - self.rebooted = 0 - self.last_reboot = None - self.dbroot = None - self.config_path = None - self.config = None - self.configure() - self.check_lastboot() - eserver.subscribe('xend.*', self.event_handler) - #eserver.subscribe('xend.domain.created', self.event_handler) - #eserver.subscribe('xend.domain.died', self.event_handler) - - def start(self): - eserver.inject('xend.start', self.rebooted) - - def event_handler(self, event, val): - print >> sys.stderr, "EVENT>", event, val - - def read_lastboot(self): - try: - val = file(self.lastboot, 'rb').readlines()[0] - except StandardError, ex: - print 'warning: Error reading', self.lastboot, ex - val = None - return val - - def write_lastboot(self, val): - if not val: return - try: - fdir = os.path.dirname(self.lastboot) - if not os.path.isdir(fdir): - os.makedirs(fdir) - out = file(self.lastboot, 'wb+') - out.write(val) - out.close() - except IOError, ex: - print 'warning: Error writing', self.lastboot, ex - pass - - def check_lastboot(self): - """Check if there has been a system reboot since we saved lastboot. - """ - last_val = self.read_lastboot() - this_val = last_reboot() - if this_val == last_val: - self.rebooted = 0 - else: - self.rebooted = 1 - self.write_lastboot(this_val) - self.last_reboot = this_val - - def get_last_reboot(self): - return self.last_reboot - - def get_rebooted(self): - return self.rebooted - - def configure(self): - self.set_config() - self.dbroot = self.get_config_value("dbroot", self.dbroot_default) - self.lastboot = self.get_config_value("lastboot", self.lastboot_default) - - def get_dbroot(self): - """Get the path to the database root. - """ - return self.dbroot - - def set_config(self): - """If the config file exists, read it. If not, ignore it. - - The config file is a sequence of sxp forms. - """ - self.config_path = os.getenv(self.config_var, self.config_default) - if os.path.exists(self.config_path): - fin = file(self.config_path, 'rb') - try: - config = sxp.parse(fin) - config.insert(0, 'config') - self.config = config - finally: - fin.close() - else: - self.config = ['config'] - - def get_config(self, name=None): - """Get the configuration element with the given name, or - the whole configuration if no name is given. - - name element name (optional) - returns config or none - """ - if name is None: - val = self.config - else: - val = sxp.child(self.config, name) - return val - - def get_config_value(self, name, val=None): - """Get the value of an atomic configuration element. - - name element name - val default value (optional, defaults to None) - returns value - """ - return sxp.child_value(self.config, name, val=val) - -def instance(): - global inst - try: - inst - except: - inst = XendRoot() - return inst diff --git a/tools/xen/lib/xend/XendVnet.py b/tools/xen/lib/xend/XendVnet.py deleted file mode 100644 index 213408e111..0000000000 --- a/tools/xen/lib/xend/XendVnet.py +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright (C) 2004 Mike Wray - -"""Handler for vnet operations. -""" - -import sxp -import XendDB - -class XendVnet: - """Index of all vnets. Singleton. - """ - - dbpath = "vnet" - - def __init__(self): - # Table of vnet info indexed by vnet id. - self.vnet = {} - self.db = XendDB.XendDB(self.dbpath) - self.vnet = self.db.fetchall("") - - def vnet_ls(self): - """List all vnets. - """ - return self.vnet.keys() - - def vnets(self): - return self.vnet.values() - - def vnet_get(self, id): - """Get a vnet. - - id vnet id - """ - return self.vnet.get(id) - - def vnet_create(self, info): - """Create a vnet. - - info config - """ - self.vnet_configure(info) - - def vnet_configure(self, info): - """Configure a vnet. - id vnet id - info config - """ - # Need to configure for real. - # Only sync if succeeded - otherwise need to back out. - self.vnet[info.id] = info - self.db.save(info.id, info) - - def vnet_delete(self, id): - """Delete a vnet. - - id vnet id - """ - # Need to delete for real. What if fails? - if id in self.vnet: - del self.vnet[id] - self.db.delete(id) - -def instance(): - global inst - try: - inst - except: - inst = XendVnet() - return inst diff --git a/tools/xen/lib/xend/__init__.py b/tools/xen/lib/xend/__init__.py deleted file mode 100644 index 8d1c8b69c3..0000000000 --- a/tools/xen/lib/xend/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tools/xen/lib/xend/encode.py b/tools/xen/lib/xend/encode.py deleted file mode 100644 index 38c9351db7..0000000000 --- a/tools/xen/lib/xend/encode.py +++ /dev/null @@ -1,165 +0,0 @@ -# Copyright (C) 2004 Mike Wray -"""Encoding for arguments to HTTP calls. - Uses the url-encoding with MIME type 'application/x-www-form-urlencoded' - if the data does not include files. Otherwise it uses the encoding with - MIME type 'multipart/form-data'. See the HTML4 spec for details. - - """ -import sys -import types -from StringIO import StringIO - -import urllib -import httplib -import random -import md5 - -# Extract from HTML4 spec. -## The following example illustrates "multipart/form-data" -## encoding. Suppose we have the following form: - -##
-##

-## What is your name?
-## What files are you sending?
-## -##

- -## If the user enters "Larry" in the text input, and selects the text -## file "file1.txt", the user agent might send back the following data: - -## Content-Type: multipart/form-data; boundary=AaB03x - -## --AaB03x -## Content-Disposition: form-data; name="submit-name" - -## Larry -## --AaB03x -## Content-Disposition: form-data; name="files"; filename="file1.txt" -## Content-Type: text/plain - -## ... contents of file1.txt ... -## --AaB03x-- - -## If the user selected a second (image) file "file2.gif", the user agent -## might construct the parts as follows: - -## Content-Type: multipart/form-data; boundary=AaB03x - -## --AaB03x -## Content-Disposition: form-data; name="submit-name" - -## Larry -## --AaB03x -## Content-Disposition: form-data; name="files" -## Content-Type: multipart/mixed; boundary=BbC04y - -## --BbC04y -## Content-Disposition: file; filename="file1.txt" -## Content-Type: text/plain - -## ... contents of file1.txt ... -## --BbC04y -## Content-Disposition: file; filename="file2.gif" -## Content-Type: image/gif -## Content-Transfer-Encoding: binary - -## ...contents of file2.gif... -## --BbC04y-- -## --AaB03x-- - -__all__ = ['encode_data', 'encode_multipart', 'encode_form', 'mime_boundary' ] - -def data_values(d): - if isinstance(d, types.DictType): - return d.items() - else: - return d - -def encode_data(d): - """Encode some data for HTTP transport. - The encoding used is stored in 'Content-Type' in the headers. - - d data - sequence of tuples or dictionary - returns a 2-tuple of the headers and the encoded data - """ - val = ({}, None) - if d is None: return val - multipart = 0 - for (k, v) in data_values(d): - if encode_isfile(v): - multipart = 1 - break - if multipart: - val = encode_multipart(d) - else: - val = encode_form(d) - return val - -def encode_isfile(v): - if isinstance(v, types.FileType): - return 1 - if hasattr(v, 'readlines'): - return 1 - return 0 - -def encode_multipart(d): - boundary = mime_boundary() - hdr = { 'Content-Type': 'multipart/form-data; boundary=' + boundary } - out = StringIO() - for (k,v) in data_values(d): - out.write('--') - out.write(boundary) - out.write('\r\n') - if encode_isfile(v): - out.write('Content-Disposition: form-data; name="') - out.write(k) - if hasattr(v, 'name'): - out.write('"; filename="') - out.write(v.name) - out.write('"\r\n') - out.write('Content-Type: application/octet-stream\r\n') - out.write('\r\n') - for l in v.readlines(): - out.write(l) - else: - out.write('Content-Disposition: form-data; name="') - out.write(k) - out.write('"\r\n') - out.write('\r\n') - out.write(str(v)) - out.write('\r\n') - out.write('--') - out.write(boundary) - out.write('--') - out.write('\r\n') - return (hdr, out.getvalue()) - -def mime_boundary(): - random.seed() - m = md5.new() - for i in range(0, 10): - c = chr(random.randint(1, 255)) - m.update(c) - b = m.hexdigest() - return b[0:16] - -def encode_form(d): - hdr = { 'Content-Type': 'application/x-www-form-urlencoded' } - val = urllib.urlencode(d) - return (hdr, val) - -def main(): - #d = {'a': 1, 'b': 'x y', 'c': file('conf.sxp') } - #d = {'a': 1, 'b': 'x y' } - d = [ ('a', 1), ('b', 'x y'), ('c', file('conf.sxp')) ] - #d = [ ('a', 1), ('b', 'x y')] - v = encode_data(d) - print v[0] - sys.stdout.write(v[1]) - print - -if __name__ == "__main__": - main() diff --git a/tools/xen/lib/xend/server/SrvBase.py b/tools/xen/lib/xend/server/SrvBase.py deleted file mode 100644 index bcff1bc3a0..0000000000 --- a/tools/xen/lib/xend/server/SrvBase.py +++ /dev/null @@ -1,137 +0,0 @@ -# Copyright (C) 2004 Mike Wray - -import cgi - -import os -import sys -import types -import StringIO - -from twisted.internet import defer -from twisted.internet import reactor -from twisted.web import error -from twisted.web import resource -from twisted.web import server - -from xen.xend import sxp -from xen.xend import PrettyPrint - -def uri_pathlist(p): - """Split a path into a list. - p path - return list of path elements - """ - l = [] - for x in p.split('/'): - if x == '': continue - l.append(x) - return l - -class SrvBase(resource.Resource): - """Base class for services. - """ - - def parse_form(self, req, method): - """Parse the data for a request, GET using the URL, POST using encoded data. - Posts should use enctype='multipart/form-data' in the
tag, - rather than 'application/x-www-form-urlencoded'. Only 'multipart/form-data' - handles file upload. - - req request - returns a cgi.FieldStorage instance - """ - env = {} - env['REQUEST_METHOD'] = method - if self.query: - env['QUERY_STRING'] = self.query - val = cgi.FieldStorage(fp=req.rfile, headers=req.headers, environ=env) - return val - - def use_sxp(self, req): - """Determine whether to send an SXP response to a request. - Uses SXP if there is no User-Agent, no Accept, or application/sxp is in Accept. - - req request - returns 1 for SXP, 0 otherwise - """ - ok = 0 - user_agent = req.getHeader('User-Agent') - accept = req.getHeader('Accept') - if (not user_agent) or (not accept) or (accept.find(sxp.mime_type) >= 0): - ok = 1 - return ok - - def get_op_method(self, op): - """Get the method for an operation. - For operation 'foo' looks for 'op_foo'. - - op operation name - returns method or None - """ - op_method_name = 'op_' + op - return getattr(self, op_method_name, None) - - def perform(self, req): - """General operation handler for posted operations. - For operation 'foo' looks for a method op_foo and calls - it with op_foo(op, req). Replies with code 500 if op_foo - is not found. - - The method must return a list when req.use_sxp is true - and an HTML string otherwise (or list). - Methods may also return a Deferred (for incomplete processing). - - req request - """ - op = req.args.get('op') - if op is None or len(op) != 1: - req.setResponseCode(404, "Invalid") - return '' - op = op[0] - op_method = self.get_op_method(op) - if op_method is None: - req.setResponseCode(501, "Not implemented") - req.setHeader("Content-Type", "text/plain") - req.write("Not implemented: " + op) - return '' - else: - val = op_method(op, req) - if isinstance(val, defer.Deferred): - val.addCallback(self._cb_perform, req, 1) - return server.NOT_DONE_YET - else: - self._cb_perform(val, req, 0) - return '' - - def _cb_perform(self, val, req, dfr): - """Callback to complete the request. - May be called from a Deferred. - """ - if isinstance(val, error.ErrorPage): - req.write(val.render(req)) - elif self.use_sxp(req): - req.setHeader("Content-Type", sxp.mime_type) - sxp.show(val, req) - else: - req.write('') - self.print_path(req) - if isinstance(val, types.ListType): - req.write('
')
-                PrettyPrint.prettyprint(val, out=req)
-                req.write('
') - else: - req.write(str(val)) - req.write('') - if dfr: - req.finish() - - def print_path(self, req): - """Print the path with hyperlinks. - """ - pathlist = [x for x in req.prepath if x != '' ] - s = "/" - req.write('

/') - for x in pathlist: - s += x + "/" - req.write(' %s/' % (s, x)) - req.write("

") diff --git a/tools/xen/lib/xend/server/SrvConsole.py b/tools/xen/lib/xend/server/SrvConsole.py deleted file mode 100644 index 59d0e5f11c..0000000000 --- a/tools/xen/lib/xend/server/SrvConsole.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright (C) 2004 Mike Wray - -from xen.xend import sxp -from xen.xend import XendConsole -from SrvDir import SrvDir - -class SrvConsole(SrvDir): - """An individual console. - """ - - def __init__(self, info): - SrvDir.__init__(self) - self.info = info - self.xc = XendConsole.instance() - - def op_disconnect(self, op, req): - val = self.xc.console_disconnect(self.info.id) - return val - - def render_POST(self, req): - return self.perform(req) - - def render_GET(self, req): - if self.use_sxp(req): - req.setHeader("Content-Type", sxp.mime_type) - sxp.show(self.info.sxpr(), out=req) - else: - req.write('') - self.print_path(req) - #self.ls() - req.write('

%s

' % self.info) - req.write('

Connect to domain %d

' - % (self.info.uri(), self.info.dom2)) - self.form(req) - req.write('') - return '' - - def form(self, req): - req.write('' % req.prePathURL()) - if self.info.connection(): - req.write('') - req.write('') diff --git a/tools/xen/lib/xend/server/SrvConsoleDir.py b/tools/xen/lib/xend/server/SrvConsoleDir.py deleted file mode 100644 index 814b448370..0000000000 --- a/tools/xen/lib/xend/server/SrvConsoleDir.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright (C) 2004 Mike Wray - -from SrvDir import SrvDir -from SrvConsole import SrvConsole -from xen.xend import XendConsole -from xen.xend import sxp - -class SrvConsoleDir(SrvDir): - """Console directory. - """ - - def __init__(self): - SrvDir.__init__(self) - self.xconsole = XendConsole.instance() - - def console(self, x): - val = None - try: - info = self.xconsole.console_get(x) - val = SrvConsole(info) - except KeyError, ex: - print 'SrvConsoleDir>', ex - pass - return val - - def get(self, x): - v = SrvDir.get(self, x) - if v is not None: - return v - v = self.console(x) - return v - - def render_GET(self, req): - if self.use_sxp(req): - req.setHeader("Content-Type", sxp.mime_type) - self.ls_console(req, 1) - else: - req.write("") - self.print_path(req) - self.ls(req) - self.ls_console(req) - #self.form(req.wfile) - req.write("") - return '' - - def ls_console(self, req, use_sxp=0): - url = req.prePathURL() - if not url.endswith('/'): - url += '/' - if use_sxp: - consoles = self.xconsole.console_ls() - sxp.show(consoles, out=req) - else: - consoles = self.xconsole.consoles() - consoles.sort(lambda x, y: cmp(x.id, y.id)) - req.write('
    ') - for c in consoles: - req.write('
  • %s
  • ' % (url, c.id, c)) - req.write('
') diff --git a/tools/xen/lib/xend/server/SrvDaemon.py b/tools/xen/lib/xend/server/SrvDaemon.py deleted file mode 100644 index c8284dc485..0000000000 --- a/tools/xen/lib/xend/server/SrvDaemon.py +++ /dev/null @@ -1,751 +0,0 @@ -########################################################### -## Xen controller daemon -## Copyright (c) 2004, K A Fraser (University of Cambridge) -## Copyright (C) 2004, Mike Wray -########################################################### - -import os -import os.path -import signal -import sys -import threading -import linecache -import socket -import pwd -import re -import StringIO - -from twisted.internet import pollreactor -pollreactor.install() - -from twisted.internet import reactor -from twisted.internet import protocol -from twisted.internet import abstract -from twisted.internet import defer - -from xen.ext import xu - -from xen.xend import sxp -from xen.xend import PrettyPrint -from xen.xend import EventServer -eserver = EventServer.instance() - -from xen.xend.server import SrvServer - -import channel -import blkif -import netif -import console -import domain -from params import * - -DEBUG = 1 - -class MgmtProtocol(protocol.DatagramProtocol): - """Handler for the management socket (unix-domain). - """ - - def __init__(self, daemon): - #protocol.DatagramProtocol.__init__(self) - self.daemon = daemon - - def write(self, data, addr): - return self.transport.write(data, addr) - - def datagramReceived(self, data, addr): - if DEBUG: print 'datagramReceived> addr=', addr, 'data=', data - io = StringIO.StringIO(data) - try: - vals = sxp.parse(io) - res = self.dispatch(vals[0]) - self.send_result(addr, res) - except SystemExit: - raise - except: - if DEBUG: - raise - else: - self.send_error(addr) - - def send_reply(self, addr, sxpr): - io = StringIO.StringIO() - sxp.show(sxpr, out=io) - io.seek(0) - self.write(io.getvalue(), addr) - - def send_result(self, addr, res): - - def fn(res, self=self, addr=addr): - self.send_reply(addr, ['ok', res]) - - if isinstance(res, defer.Deferred): - res.addCallback(fn) - else: - fn(res) - - def send_error(self, addr): - (extype, exval) = sys.exc_info()[:2] - self.send_reply(addr, ['err', - ['type', str(extype) ], - ['value', str(exval) ] ] ) - - def opname(self, name): - """Get the name of the method for an operation. - """ - return 'op_' + name.replace('.', '_') - - def operror(self, name, v): - """Default operation handler - signals an error. - """ - raise NotImplementedError('Invalid operation: ' +name) - - def dispatch(self, req): - """Dispatch a request to its handler. - """ - op_name = sxp.name(req) - op_method_name = self.opname(op_name) - op_method = getattr(self, op_method_name, self.operror) - return op_method(op_name, req) - - def op_console_create(self, name, req): - """Create a new control interface - console for a domain. - """ - print name, req - dom = sxp.child_value(req, 'domain') - if not dom: raise ValueError('Missing domain') - dom = int(dom) - console_port = sxp.child_value(req, 'console_port') - if console_port: - console_port = int(console_port) - resp = self.daemon.console_create(dom, console_port) - print name, resp - return resp - - def op_consoles(self, name, req): - """Get a list of the consoles. - """ - return self.daemon.consoles() - - def op_console_disconnect(self, name, req): - id = sxp.child_value(req, 'id') - if not id: - raise ValueError('Missing console id') - id = int(id) - console = self.daemon.get_console(id) - if not console: - raise ValueError('Invalid console id') - if console.conn: - console.conn.loseConnection() - return ['ok'] - - def op_blkifs(self, name, req): - pass - - def op_blkif_devs(self, name, req): - pass - - def op_blkif_create(self, name, req): - pass - - def op_blkif_dev_create(self, name, req): - pass - - def op_netifs(self, name, req): - pass - - def op_netif_devs(self, name, req): - pass - - def op_netif_create(self, name, req): - pass - - def op_netif_dev_create(self, name, req): - pass - -class NotifierProtocol(protocol.Protocol): - """Asynchronous handler for i/o on the notifier (event channel). - """ - - def __init__(self, channelFactory): - self.channelFactory = channelFactory - - def notificationReceived(self, idx, type): - #print 'NotifierProtocol>notificationReceived>', idx, type - channel = self.channelFactory.getChannel(idx) - if not channel: - return - #print 'NotifierProtocol>notificationReceived> channel', channel - channel.notificationReceived(type) - - def connectionLost(self, reason=None): - pass - - def doStart(self): - pass - - def doStop(self): - pass - - def startProtocol(self): - pass - - def stopProtocol(self): - pass - -class NotifierPort(abstract.FileDescriptor): - """Transport class for the event channel. - """ - - def __init__(self, daemon, notifier, proto, reactor=None): - assert isinstance(proto, NotifierProtocol) - abstract.FileDescriptor.__init__(self, reactor) - self.daemon = daemon - self.notifier = notifier - self.protocol = proto - - def startListening(self): - self._bindNotifier() - self._connectToProtocol() - - def stopListening(self): - if self.connected: - result = self.d = defer.Deferred() - else: - result = None - self.loseConnection() - return result - - def fileno(self): - return self.notifier.fileno() - - def _bindNotifier(self): - self.connected = 1 - - def _connectToProtocol(self): - self.protocol.makeConnection(self) - self.startReading() - - def loseConnection(self): - if self.connected: - self.stopReading() - self.disconnecting = 1 - reactor.callLater(0, self.connectionLost) - - def connectionLost(self, reason=None): - abstract.FileDescriptor.connectionLost(self, reason) - if hasattr(self, 'protocol'): - self.protocol.doStop() - self.connected = 0 - #self.notifier.close() # Not implemented. - os.close(self.fileno()) - del self.notifier - if hasattr(self, 'd'): - self.d.callback(None) - del self.d - - def doRead(self): - #print 'NotifierPort>doRead>', self - count = 0 - while 1: - #print 'NotifierPort>doRead>', count - notification = self.notifier.read() - if not notification: - break - (idx, type) = notification - self.protocol.notificationReceived(idx, type) - self.notifier.unmask(idx) - count += 1 - #print 'NotifierPort>doRead<' - -class EventProtocol(protocol.Protocol): - """Asynchronous handler for a connected event socket. - """ - - def __init__(self, daemon): - #protocol.Protocol.__init__(self) - self.daemon = daemon - # Event queue. - self.queue = [] - # Subscribed events. - self.events = [] - self.parser = sxp.Parser() - self.pretty = 0 - - # For debugging subscribe to everything and make output pretty. - self.subscribe(['*']) - self.pretty = 1 - - def dataReceived(self, data): - try: - self.parser.input(data) - if self.parser.ready(): - val = self.parser.get_val() - res = self.dispatch(val) - self.send_result(res) - if self.parser.at_eof(): - self.loseConnection() - except SystemExit: - raise - except: - if DEBUG: - raise - else: - self.send_error() - - def loseConnection(self): - if self.transport: - self.transport.loseConnection() - if self.connected: - reactor.callLater(0, self.connectionLost) - - def connectionLost(self, reason=None): - self.unsubscribe() - - def send_reply(self, sxpr): - io = StringIO.StringIO() - if self.pretty: - PrettyPrint.prettyprint(sxpr, out=io) - else: - sxp.show(sxpr, out=io) - print >> io - io.seek(0) - return self.transport.write(io.getvalue()) - - def send_result(self, res): - return self.send_reply(['ok', res]) - - def send_error(self): - (extype, exval) = sys.exc_info()[:2] - return self.send_reply(['err', - ['type', str(extype)], - ['value', str(exval)]]) - - def send_event(self, val): - return self.send_reply(['event', val[0], val[1]]) - - def unsubscribe(self): - for event in self.events: - eserver.unsubscribe(event, self.queue_event) - - def subscribe(self, events): - self.unsubscribe() - for event in events: - eserver.subscribe(event, self.queue_event) - self.events = events - - def queue_event(self, name, v): - # Despite the name we dont' queue the event here. - # We send it because the transport will queue it. - self.send_event([name, v]) - - def opname(self, name): - return 'op_' + name.replace('.', '_') - - def operror(self, name, req): - raise NotImplementedError('Invalid operation: ' +name) - - def dispatch(self, req): - op_name = sxp.name(req) - op_method_name = self.opname(op_name) - op_method = getattr(self, op_method_name, self.operror) - return op_method(op_name, req) - - def op_help(self, name, req): - def nameop(x): - if x.startswith('op_'): - return x[3:].replace('_', '.') - else: - return x - - l = [ nameop(k) for k in dir(self) if k.startswith('op_') ] - return l - - def op_quit(self, name, req): - self.loseConnection() - - def op_exit(self, name, req): - sys.exit(0) - - def op_pretty(self, name, req): - self.pretty = 1 - return ['ok'] - - def op_console_disconnect(self, name, req): - id = sxp.child_value(req, 'id') - if not id: - raise ValueError('Missing console id') - self.daemon.console_disconnect(id) - return ['ok'] - - def op_info(self, name, req): - val = ['info'] - val += self.daemon.consoles() - val += self.daemon.blkifs() - val += self.daemon.netifs() - return val - - def op_sys_subscribe(self, name, v): - # (sys.subscribe event*) - # Subscribe to the events: - self.subscribe(v[1:]) - return ['ok'] - - def op_sys_inject(self, name, v): - # (sys.inject event) - event = v[1] - eserver.inject(sxp.name(event), event) - return ['ok'] - - -class EventFactory(protocol.Factory): - """Asynchronous handler for the event server socket. - """ - protocol = EventProtocol - service = None - - def __init__(self, daemon): - #protocol.Factory.__init__(self) - self.daemon = daemon - - def buildProtocol(self, addr): - proto = self.protocol(self.daemon) - proto.factory = self - return proto - -class VirqClient: - def __init__(self, daemon): - self.daemon = daemon - - def virqReceived(self, virq): - print 'VirqClient.virqReceived>', virq - eserver.inject('xend.virq', virq) - - def lostChannel(self, channel): - print 'VirqClient.lostChannel>', channel - -class Daemon: - """The xend daemon. - """ - def __init__(self): - self.shutdown = 0 - - def daemon_pids(self): - pids = [] - pidex = '(?P\d+)' - pythonex = '(?P\S*python\S*)' - cmdex = '(?P.*)' - procre = re.compile('^\s*' + pidex + '\s*' + pythonex + '\s*' + cmdex + '$') - xendre = re.compile('^/usr/sbin/xend\s*(start|restart)\s*.*$') - procs = os.popen('ps -e -o pid,args 2>/dev/null') - for proc in procs: - pm = procre.match(proc) - if not pm: continue - xm = xendre.match(pm.group('cmd')) - if not xm: continue - #print 'pid=', pm.group('pid'), 'cmd=', pm.group('cmd') - pids.append(int(pm.group('pid'))) - return pids - - def new_cleanup(self, kill=0): - err = 0 - pids = self.daemon_pids() - if kill: - for pid in pids: - print "Killing daemon pid=%d" % pid - os.kill(pid, signal.SIGHUP) - elif pids: - err = 1 - print "Daemon already running: ", pids - return err - - def cleanup(self, kill=False): - # No cleanup to do if PID_FILE is empty. - if not os.path.isfile(PID_FILE) or not os.path.getsize(PID_FILE): - return 0 - # Read the pid of the previous invocation and search active process list. - pid = open(PID_FILE, 'r').read() - lines = os.popen('ps ' + pid + ' 2>/dev/null').readlines() - for line in lines: - if re.search('^ *' + pid + '.+xend', line): - if not kill: - print "Daemon is already running (pid %d)" % int(pid) - return 1 - # Old daemon is still active: terminate it. - os.kill(int(pid), 1) - # Delete the stale PID_FILE. - os.remove(PID_FILE) - return 0 - - def install_child_reaper(self): - #signal.signal(signal.SIGCHLD, self.onSIGCHLD) - # Ensure that zombie children are automatically reaped. - xu.autoreap() - - def onSIGCHLD(self, signum, frame): - code = 1 - while code > 0: - code = os.waitpid(-1, os.WNOHANG) - - def start(self,trace=0): - if self.cleanup(kill=False): - return 1 - - # Detach from TTY. - if not DEBUG: - os.setsid() - - if self.set_user(): - return 1 - - self.install_child_reaper() - - # Fork -- parent writes PID_FILE and exits. - pid = os.fork() - if pid: - # Parent - pidfile = open(PID_FILE, 'w') - pidfile.write(str(pid)) - pidfile.close() - return 0 - # Child - logfile = self.open_logfile() - self.redirect_output(logfile) - if trace: - self.tracefile = open('/var/log/xend.trace', 'w+', 1) - self.traceindent = 0 - sys.settrace(self.trace) - try: - threading.settrace(self.trace) # Only in Python >= 2.3 - except: - pass - self.run() - return 0 - - def print_trace(self,str): - for i in range(self.traceindent): - self.tracefile.write(" ") - self.tracefile.write(str) - - def trace(self, frame, event, arg): - if event == 'call': - code = frame.f_code - filename = code.co_filename - m = re.search('.*xenmgr/(.*)', code.co_filename) - if not m: - return None - modulename = m.group(1) - if re.search('sxp.py', modulename): - return None - self.traceindent += 1 - self.print_trace("++++ %s:%s\n" - % (modulename, code.co_name)) - elif event == 'line': - filename = frame.f_code.co_filename - lineno = frame.f_lineno - self.print_trace("%4d %s" % - (lineno, linecache.getline(filename, lineno))) - elif event == 'return': - code = frame.f_code - filename = code.co_filename - m = re.search('.*xenmgr/(.*)', code.co_filename) - if not m: - return None - modulename = m.group(1) - self.print_trace("---- %s:%s\n" - % (modulename, code.co_name)) - self.traceindent -= 1 - elif event == 'exception': - pass - return self.trace - - def open_logfile(self): - if not os.path.exists(CONTROL_DIR): - os.makedirs(CONTROL_DIR) - - # Open log file. Truncate it if non-empty, and request line buffering. - if os.path.isfile(LOG_FILE): - os.rename(LOG_FILE, LOG_FILE+'.old') - logfile = open(LOG_FILE, 'w+', 1) - return logfile - - def set_user(self): - # Set the UID. - try: - os.setuid(pwd.getpwnam(USER)[2]) - return 0 - except KeyError, error: - print "Error: no such user '%s'" % USER - return 1 - - def redirect_output(self, logfile): - if DEBUG: return - # Close down standard file handles - try: - os.close(0) # stdin - os.close(1) # stdout - os.close(2) # stderr - except: - pass - # Redirect output to log file. - sys.stdout = sys.stderr = logfile - - def stop(self): - return self.cleanup(kill=True) - - def run(self): - self.createFactories() - self.listenMgmt() - self.listenEvent() - self.listenNotifier() - self.listenVirq() - SrvServer.create(bridge=1) - reactor.run() - - def createFactories(self): - self.channelF = channel.channelFactory() - self.domainCF = domain.DomainControllerFactory() - self.blkifCF = blkif.BlkifControllerFactory() - self.netifCF = netif.NetifControllerFactory() - self.consoleCF = console.ConsoleControllerFactory() - - def listenMgmt(self): - protocol = MgmtProtocol(self) - s = os.path.join(CONTROL_DIR, MGMT_SOCK) - if os.path.exists(s): - os.unlink(s) - return reactor.listenUNIXDatagram(s, protocol) - - def listenEvent(self): - protocol = EventFactory(self) - return reactor.listenTCP(EVENT_PORT, protocol) - - def listenNotifier(self): - protocol = NotifierProtocol(self.channelF) - p = NotifierPort(self, self.channelF.notifier, protocol, reactor) - p.startListening() - return p - - def listenVirq(self): - virqChan = self.channelF.virqChannel(channel.VIRQ_DOM_EXC) - virqChan.registerClient(VirqClient(self)) - - def exit(self): - reactor.diconnectAll() - sys.exit(0) - - def blkif_set_control_domain(self, dom, recreate=0): - """Set the block device backend control domain. - """ - return self.blkifCF.setControlDomain(dom, recreate=recreate) - - def blkif_get_control_domain(self, dom): - """Get the block device backend control domain. - """ - return self.blkifCF.getControlDomain() - - def blkif_create(self, dom, recreate=0): - """Create a block device interface controller. - - Returns Deferred - """ - d = self.blkifCF.createInstance(dom, recreate=recreate) - return d - - def blkifs(self): - return [ x.sxpr() for x in self.blkifCF.getInstances() ] - - def blkif_get(self, dom): - return self.blkifCF.getInstanceByDom(dom) - - def blkif_dev(self, dom, vdev): - return self.blkifCF.getDomainDevice(dom, vdev) - - def blkif_dev_create(self, dom, vdev, mode, segment, recreate=0): - """Create a block device. - - Returns Deferred - """ - ctrl = self.blkifCF.getInstanceByDom(dom) - if not ctrl: - raise ValueError('No blkif controller: %d' % dom) - print 'blkif_dev_create>', dom, vdev, mode, segment - d = ctrl.attachDevice(vdev, mode, segment, recreate=recreate) - return d - - def netif_set_control_domain(self, dom, recreate=0): - """Set the network interface backend control domain. - """ - return self.netifCF.setControlDomain(dom, recreate=recreate) - - def netif_get_control_domain(self, dom): - """Get the network interface backend control domain. - """ - return self.netifCF.getControlDomain() - - def netif_create(self, dom, recreate=0): - """Create a network interface controller. - - """ - return self.netifCF.createInstance(dom, recreate=recreate) - - def netifs(self): - return [ x.sxpr() for x in self.netifCF.getInstances() ] - - def netif_get(self, dom): - return self.netifCF.getInstanceByDom(dom) - - def netif_dev_create(self, dom, vif, vmac, recreate=0): - """Create a network device. - - todo - """ - ctrl = self.netifCF.getInstanceByDom(dom) - if not ctrl: - raise ValueError('No netif controller: %d' % dom) - d = ctrl.attachDevice(vif, vmac, recreate=recreate) - return d - - def netif_dev(self, dom, vif): - return self.netifCF.getDomainDevice(dom, vif) - - def console_create(self, dom, console_port=None): - """Create a console for a domain. - """ - console = self.consoleCF.getInstanceByDom(dom) - if console is None: - console = self.consoleCF.createInstance(dom, console_port) - return console.sxpr() - - def consoles(self): - return [ c.sxpr() for c in self.consoleCF.getInstances() ] - - def get_console(self, id): - return self.consoleCF.getInstance(id) - - def get_domain_console(self, dom): - return self.consoleCF.getInstanceByDom(dom) - - def console_disconnect(self, id): - """Disconnect any connected console client. - """ - console = self.get_console(id) - if not console: - raise ValueError('Invalid console id') - console.disconnect() - - def domain_shutdown(self, dom, reason): - """Shutdown a domain. - """ - ctrl = self.domainCF.getInstanceByDom(dom) - if not ctrl: - raise ValueError('No domain controller: %d' % dom) - ctrl.shutdown(reason) - return 0 - -def instance(): - global inst - try: - inst - except: - inst = Daemon() - return inst diff --git a/tools/xen/lib/xend/server/SrvDeviceDir.py b/tools/xen/lib/xend/server/SrvDeviceDir.py deleted file mode 100644 index 52f428540d..0000000000 --- a/tools/xen/lib/xend/server/SrvDeviceDir.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (C) 2004 Mike Wray - -from SrvDir import SrvDir - -class SrvDeviceDir(SrvDir): - """Device directory. - """ - - pass diff --git a/tools/xen/lib/xend/server/SrvDir.py b/tools/xen/lib/xend/server/SrvDir.py deleted file mode 100644 index c49c0b36ba..0000000000 --- a/tools/xen/lib/xend/server/SrvDir.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright (C) 2004 Mike Wray - -from twisted.web import error -from xen.xend import sxp -from SrvBase import SrvBase - -class SrvConstructor: - """Delayed constructor for sub-servers. - Does not import the sub-server class or create the object until needed. - """ - - def __init__(self, klass): - """Create a constructor. It is assumed that the class - should be imported as 'import klass from klass'. - - klass name of its class - """ - self.klass = klass - self.obj = None - - def getobj(self): - """Get the sub-server object, importing its class and instantiating it if - necessary. - """ - if not self.obj: - exec 'from %s import %s' % (self.klass, self.klass) - klassobj = eval(self.klass) - self.obj = klassobj() - return self.obj - -class SrvDir(SrvBase): - """Base class for directory servlets. - """ - isLeaf = False - - def __init__(self): - SrvBase.__init__(self) - self.table = {} - self.order = [] - - def getChild(self, x, req): - if x == '': return self - val = self.get(x) - if val is None: - return error.NoResource('Not found') - else: - return val - - def get(self, x): - val = self.table.get(x) - if val is not None: - val = val.getobj() - return val - - def add(self, x, xclass = None): - if xclass is None: - xclass = 'SrvDir' - self.table[x] = SrvConstructor(xclass) - self.order.append(x) - - def render_GET(self, req): - if self.use_sxp(req): - req.setHeader("Content-type", sxp.mime_type) - self.ls(req, 1) - else: - req.write('') - self.print_path(req) - self.ls(req) - self.form(req) - req.write('') - return '' - - def ls(self, req, use_sxp=0): - url = req.prePathURL() - if not url.endswith('/'): - url += '/' - if use_sxp: - req.write('(ls ') - for k in self.order: - req.write(' ' + k) - req.write(')') - else: - req.write('
    ') - for k in self.order: - v = self.get(k) - req.write('
  • %s
  • ' - % (url, k, k)) - req.write('
') - - def form(self, req): - pass diff --git a/tools/xen/lib/xend/server/SrvDomain.py b/tools/xen/lib/xend/server/SrvDomain.py deleted file mode 100644 index 156198bd70..0000000000 --- a/tools/xen/lib/xend/server/SrvDomain.py +++ /dev/null @@ -1,195 +0,0 @@ -# Copyright (C) 2004 Mike Wray - -from xen.xend import sxp -from xen.xend import XendDomain -from xen.xend import XendConsole -from xen.xend import PrettyPrint -from xen.xend.Args import FormFn - -from SrvDir import SrvDir - -class SrvDomain(SrvDir): - """Service managing a single domain. - """ - - def __init__(self, dom): - SrvDir.__init__(self) - self.dom = dom - self.xd = XendDomain.instance() - self.xconsole = XendConsole.instance() - - def op_unpause(self, op, req): - val = self.xd.domain_unpause(self.dom.id) - return val - - def op_pause(self, op, req): - val = self.xd.domain_pause(self.dom.id) - return val - - def op_shutdown(self, op, req): - val = self.xd.domain_shutdown(self.dom.id) - req.setResponseCode(202) - req.setHeader("Location", "%s/.." % req.prePathURL()) - return val - - def op_destroy(self, op, req): - val = self.xd.domain_destroy(self.dom.id) - req.setHeader("Location", "%s/.." % req.prePathURL()) - return val - - def op_save(self, op, req): - fn = FormFn(self.xd.domain_save, - [['dom', 'int'], - ['file', 'str']]) - val = fn(req.args, {'dom': self.dom.id}) - return val - - def op_migrate(self, op, req): - fn = FormFn(self.xd.domain_migrate, - [['dom', 'int'], - ['destination', 'str']]) - val = fn(req.args, {'dom': self.dom.id}) - val = 0 # Some migrate id. - req.setResponseCode(202) - #req.send_header("Location", "%s/.." % self.path) # Some migrate url. - return val - - def op_pincpu(self, op, req): - fn = FormFn(self.xd.domain_pincpu, - [['dom', 'int'], - ['cpu', 'int']]) - val = fn(req.args, {'dom': self.dom.id}) - return val - - def op_cpu_bvt_set(self, op, req): - fn = FormFn(self.xd.domain_cpu_bvt_set, - [['dom', 'int'], - ['mcuadv', 'int'], - ['warp', 'int'], - ['warpl', 'int'], - ['warpu', 'int']]) - val = fn(req.args, {'dom': self.dom.id}) - return val - - def op_cpu_atropos_set(self, op, req): - fn = FormFn(self.xd.domain_cpu_atropos_set, - [['dom', 'int'], - ['period', 'int'], - ['slice', 'int'], - ['latency', 'int'], - ['xtratime', 'int']]) - val = fn(req.args, {'dom': self.dom.id}) - return val - - def op_vifs(self, op, req): - return self.xd.domain_vif_ls(self.dom.id) - - def op_vif(self, op, req): - fn = FormFn(self.xd.domain_vif_get, - [['dom', 'int'], - ['vif', 'int']]) - val = fn(req.args, {'dom': self.dom.id}) - return val - - def op_vif_stats(self, op, req): - #todo - fn = FormFn(self.xd.domain_vif_stats, - [['dom', 'int'], - ['vif', 'int']]) - #val = fn(req.args, {'dom': self.dom.id}) - val = 999 - #return val - return val - - def op_vif_ip_add(self, op, req): - fn = FormFn(self.xd.domain_vif_ip_add, - [['dom', 'int'], - ['vif', 'int'], - ['ip', 'str']]) - val = fn(req.args, {'dom': self.dom.id}) - return val - - def op_vif_scheduler_set(self, op, req): - fn = FormFn(self.xd.domain_vif_scheduler_set, - [['dom', 'int'], - ['vif', 'int'], - ['bytes', 'int'], - ['usecs', 'int']]) - val = fn(req.args, {'dom': self.dom.id}) - return val - - def op_vif_scheduler_get(self, op, req): - fn = FormFn(self.xd.domain_vif_scheduler_set, - [['dom', 'int'], - ['vif', 'int']]) - val = fn(req.args, {'dom': self.dom.id}) - return val - - def op_vbds(self, op, req): - return self.xd.domain_vbd_ls(self.dom.id) - - def op_vbd(self, op, req): - fn = FormFn(self.xd.domain_vbd_get, - [['dom', 'int'], - ['vbd', 'int']]) - val = fn(req.args, {'dom': self.dom.id}) - return val - - def op_vbd_add(self, op, req): - fn = FormFn(self.xd.domain_vbd_add, - [['dom', 'int'], - ['uname', 'str'], - ['dev', 'str'], - ['mode', 'str']]) - val = fn(req.args, {'dom': self.dom.id}) - return val - - def op_vbd_remove(self, op, req): - fn = FormFn(self.xd.domain_vbd_remove, - [['dom', 'int'], - ['dev', 'str']]) - val = fn(req.args, {'dom': self.dom.id}) - return val - - def render_POST(self, req): - return self.perform(req) - - def render_GET(self, req): - op = req.args.get('op') - if op and op[0] in ['vifs', 'vif', 'vif_stats', 'vbds', 'vbd']: - return self.perform(req) - if self.use_sxp(req): - req.setHeader("Content-Type", sxp.mime_type) - sxp.show(self.dom.sxpr(), out=req) - else: - req.write('') - self.print_path(req) - #self.ls() - req.write('

%s

' % self.dom) - if self.dom.console: - cinfo = self.dom.console - cid = cinfo.id - #todo: Local xref: need to know server prefix. - req.write('

Console %s

' - % (cid, cid)) - req.write('

Connect to console

' - % cinfo.uri()) - if self.dom.config: - req.write("
")
-                PrettyPrint.prettyprint(self.dom.config, out=req)
-                req.write("
") - req.write('vif 0 stats' - % req.prePathURL()) - self.form(req) - req.write('') - return '' - - def form(self, req): - req.write('
' % req.prePathURL()) - req.write('') - req.write('') - req.write('') - req.write('') - req.write('
') - req.write('To: ') - req.write('
') diff --git a/tools/xen/lib/xend/server/SrvDomainDir.py b/tools/xen/lib/xend/server/SrvDomainDir.py deleted file mode 100644 index af4bc7a15c..0000000000 --- a/tools/xen/lib/xend/server/SrvDomainDir.py +++ /dev/null @@ -1,144 +0,0 @@ -# Copyright (C) 2004 Mike Wray - -from StringIO import StringIO - -from twisted.protocols import http -from twisted.web import error - -from xen.xend import sxp -from xen.xend import XendDomain -from xen.xend.Args import FormFn - -from SrvDir import SrvDir -from SrvDomain import SrvDomain - -class SrvDomainDir(SrvDir): - """Service that manages the domain directory. - """ - - def __init__(self): - SrvDir.__init__(self) - self.xd = XendDomain.instance() - - def domain(self, x): - val = None - try: - dom = self.xd.domain_get(x) - val = SrvDomain(dom) - except KeyError, ex: - print 'SrvDomainDir>', ex - pass - return val - - def get(self, x): - v = SrvDir.get(self, x) - if v is not None: - return v - v = self.domain(x) - return v - - def op_create(self, op, req): - ok = 0 - try: - configstring = req.args.get('config')[0] - print 'config:', configstring - pin = sxp.Parser() - pin.input(configstring) - pin.input_eof() - config = pin.get_val() - ok = 1 - except Exception, ex: - print 'op_create>', ex - if not ok: - req.setResponseCode(http.BAD_REQUEST, "Invalid configuration") - return "Invalid configuration" - return error.ErrorPage(http.BAD_REQUEST, - "Invalid", - "Invalid configuration") - try: - deferred = self.xd.domain_create(config) - deferred.addCallback(self._cb_op_create, configstring, req) - return deferred - except Exception, ex: - raise - #return ['err', str(ex) ] - #req.setResponseCode(http.BAD_REQUEST, "Error creating domain") - #return str(ex) - #return error.ErrorPage(http.BAD_REQUEST, - # "Error creating domain", - # str(ex)) - - - def _cb_op_create(self, dominfo, configstring, req): - """Callback to handle deferred domain creation. - """ - dom = dominfo.id - domurl = "%s/%s" % (req.prePathURL(), dom) - req.setResponseCode(201, "created") - req.setHeader("Location", domurl) - if self.use_sxp(req): - return dominfo.sxpr() - else: - out = StringIO() - print >> out, ('

Created Domain %s

' - % (domurl, dom)) - print >> out, '

'
-            print >> out, configstring
-            print >> out, '

' - val = out.getvalue() - out.close() - return val - - def op_restore(self, op, req): - fn = FormFn(self.xd.domain_restore, - [['file', 'str']]) - val = fn(req.args) - return val - - def render_POST(self, req): - return self.perform(req) - - def render_GET(self, req): - if self.use_sxp(req): - req.setHeader("Content-Type", sxp.mime_type) - self.ls_domain(req, 1) - else: - req.write("") - self.print_path(req) - self.ls(req) - self.ls_domain(req) - self.form(req) - req.write("") - return '' - - def ls_domain(self, req, use_sxp=0): - url = req.prePathURL() - if not url.endswith('/'): - url += '/' - if use_sxp: - domains = self.xd.domain_ls() - sxp.show(domains, out=req) - else: - domains = self.xd.domains() - domains.sort(lambda x, y: cmp(x.id, y.id)) - req.write('
    ') - for d in domains: - req.write('
  • Domain %s' - % (url, d.id, d.id)) - req.write('name=%s' % d.name) - req.write('memory=%d'% d.memory) - req.write('
  • ') - req.write('
') - - def form(self, req): - req.write('
' - % req.prePathURL()) - req.write('') - req.write('Config
') - req.write('
') - req.write('
' - % req.prePathURL()) - req.write('') - req.write('State
') - req.write('
') - diff --git a/tools/xen/lib/xend/server/SrvEventDir.py b/tools/xen/lib/xend/server/SrvEventDir.py deleted file mode 100644 index 02871a426a..0000000000 --- a/tools/xen/lib/xend/server/SrvEventDir.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright (C) 2004 Mike Wray - -from xen.xend import sxp -from xen.xend import EventServer -from SrvDir import SrvDir - -class SrvEventDir(SrvDir): - """Event directory. - """ - - def __init__(self): - SrvDir.__init__(self) - self.eserver = EventServer.instance() - - def op_inject(self, op, req): - eventstring = req.args.get('event') - pin = sxp.Parser() - pin.input(eventstring) - pin.input_eof() - sxpr = pin.get_val() - self.eserver.inject(sxp.name(sxpr), sxpr) - if req.use_sxp: - sxp.name(sxpr) - else: - return '' + eventstring + '' - - def render_POST(self, req): - return self.perform(req) - - def form(self, req): - action = req.prePathURL() - req.write('
' - % action) - req.write('') - req.write('Event
') - req.write('
') - req.write('
' - % action) - req.write('') - req.write('Event file
') - req.write('
') diff --git a/tools/xen/lib/xend/server/SrvNode.py b/tools/xen/lib/xend/server/SrvNode.py deleted file mode 100644 index 69747d80c1..0000000000 --- a/tools/xen/lib/xend/server/SrvNode.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright (C) 2004 Mike Wray - -import os -from SrvDir import SrvDir -from xen.xend import sxp -from xen.xend import XendNode - -class SrvNode(SrvDir): - """Information about the node. - """ - - def __init__(self): - SrvDir.__init__(self) - self.xn = XendNode.instance() - - def op_shutdown(self, op, req): - val = self.xn.shutdown() - return val - - def op_reboot(self, op, req): - val = self.xn.reboot() - return val - - def op_cpu_rrobin_slice_set(self, op, req): - fn = FormFn(self.xn.cpu_rrobin_slice_set, - [['slice', 'int']]) - val = fn(req.args, {}) - return val - - def op_cpu_bvt_slice_set(self, op, req): - fn = FormFn(self.xn.cpu_bvt_slice_set, - [['slice', 'int']]) - val = fn(req.args, {}) - return val - - def render_POST(self, req): - return self.perform(req) - - def render_GET(self, req): - if self.use_sxp(req): - req.setHeader("Content-Type", sxp.mime_type) - sxp.show(['node'] + self.info(), out=req) - else: - req.write('') - self.print_path(req) - req.write('
    ') - for d in self.info(): - req.write('
  • %10s: %s' % (d[0], str(d[1]))) - req.write('
') - req.write('') - return '' - - def info(self): - return self.xn.info() diff --git a/tools/xen/lib/xend/server/SrvRoot.py b/tools/xen/lib/xend/server/SrvRoot.py deleted file mode 100644 index 8d38937b72..0000000000 --- a/tools/xen/lib/xend/server/SrvRoot.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright (C) 2004 Mike Wray - -from xen.xend import XendRoot -xroot = XendRoot.instance() -from SrvDir import SrvDir - -class SrvRoot(SrvDir): - """The root of the xend server. - """ - - """Server sub-components. Each entry is (name, class), where - 'name' is the entry name and 'class' is the name of its class. - """ - #todo Get this list from the XendRoot config. - subdirs = [ - ('node', 'SrvNode' ), - ('domain', 'SrvDomainDir' ), - ('console', 'SrvConsoleDir' ), - ('event', 'SrvEventDir' ), - ('device', 'SrvDeviceDir' ), - ('vnet', 'SrvVnetDir' ), - ] - - def __init__(self): - SrvDir.__init__(self) - for (name, klass) in self.subdirs: - self.add(name, klass) - for (name, klass) in self.subdirs: - self.get(name) - xroot.start() diff --git a/tools/xen/lib/xend/server/SrvServer.py b/tools/xen/lib/xend/server/SrvServer.py deleted file mode 100644 index ac201dd10d..0000000000 --- a/tools/xen/lib/xend/server/SrvServer.py +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/python2 -# Copyright (C) 2004 Mike Wray - -"""Example xend HTTP and console server. - - Can be accessed from a browser or from a program. - Do 'python SrvServer.py' to run the server. - Then point a web browser at http://localhost:8000/xend and follow the links. - Most are stubs, except /domain which has a list of domains and a 'create domain' - button. - - You can also access the server from a program. - Do 'python XendClient.py' to run a few test operations. - - The data served differs depending on the client (as defined by User-Agent - and Accept in the HTTP headers). If the client is a browser, data - is returned in HTML, with interactive forms. If the client is a program, - data is returned in SXP format, with no forms. - - The server serves to the world by default. To restrict it to the local host - change 'interface' in main(). - - Mike Wray -""" -# todo Support security settings etc. in the config file. -# todo Support command-line args. - -from twisted.web import server -from twisted.web import resource -from twisted.internet import reactor - -from xen.xend import XendRoot -xroot = XendRoot.instance() - -from xen.xend import Vifctl - -from SrvRoot import SrvRoot - -def create(port=None, interface=None, bridge=0): - if port is None: port = 8000 - if interface is None: interface = '' - if bridge or xroot.rebooted: - init_bridge() - root = resource.Resource() - xend = SrvRoot() - root.putChild('xend', xend) - site = server.Site(root) - reactor.listenTCP(port, site, interface=interface) - -def init_bridge(): - Vifctl.init() - -def main(port=None, interface=None): - create(port, interface) - reactor.run() - - -if __name__ == '__main__': - main() diff --git a/tools/xen/lib/xend/server/SrvVnetDir.py b/tools/xen/lib/xend/server/SrvVnetDir.py deleted file mode 100644 index a8a814192d..0000000000 --- a/tools/xen/lib/xend/server/SrvVnetDir.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (C) 2004 Mike Wray - -from SrvDir import SrvDir - -class SrvVnetDir(SrvDir): - """Vnet directory. - """ - - pass diff --git a/tools/xen/lib/xend/server/__init__.py b/tools/xen/lib/xend/server/__init__.py deleted file mode 100644 index 8b13789179..0000000000 --- a/tools/xen/lib/xend/server/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tools/xen/lib/xend/server/blkif.py b/tools/xen/lib/xend/server/blkif.py deleted file mode 100755 index 4e2a49f7d8..0000000000 --- a/tools/xen/lib/xend/server/blkif.py +++ /dev/null @@ -1,341 +0,0 @@ -from twisted.internet import defer - -from xen.xend import sxp -from xen.xend import PrettyPrint - -import channel -import controller -from messages import * - -class BlkifControllerFactory(controller.ControllerFactory): - """Factory for creating block device interface controllers. - Also handles the 'back-end' channel to the device driver domain. - """ - - def __init__(self): - controller.ControllerFactory.__init__(self) - - self.majorTypes = [ CMSG_BLKIF_BE ] - - self.subTypes = { - CMSG_BLKIF_BE_CREATE : self.recv_be_create, - CMSG_BLKIF_BE_CONNECT : self.recv_be_connect, - CMSG_BLKIF_BE_VBD_CREATE : self.recv_be_vbd_create, - CMSG_BLKIF_BE_VBD_GROW : self.recv_be_vbd_grow, - CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED: self.recv_be_driver_status_changed, - } - self.attached = 1 - self.registerChannel() - - def createInstance(self, dom, recreate=0): - d = self.addDeferred() - blkif = self.getInstanceByDom(dom) - if blkif: - self.callDeferred(blkif) - else: - blkif = BlkifController(self, dom) - self.addInstance(blkif) - if recreate: - self.callDeferred(blkif) - else: - blkif.send_be_create() - return d - - def getDomainDevices(self, dom): - blkif = self.getInstanceByDom(dom) - return (blkif and blkif.getDevices()) or [] - - def getDomainDevice(self, dom, vdev): - blkif = self.getInstanceByDom(dom) - return (blkif and blkif.getDevice(vdev)) or None - - def setControlDomain(self, dom, recreate=0): - if self.dom == dom: return - self.deregisterChannel() - if not recreate: - self.attached = 0 - self.dom = dom - self.registerChannel() - # - #if xend.blkif.be_port: - # xend.blkif.recovery = True - #xend.blkif.be_port = xend.main.port_from_dom(dom) - - def getControlDomain(self): - return self.dom - - def reattachDevice(self, dom, vdev): - blkif = self.getInstanceByDom(dom) - if blkif: - blkif.reattachDevice(vdev) - self.attached = self.devicesAttached() - if self.attached: - self.reattached() - - def devicesAttached(self): - """Check if all devices are attached. - """ - attached = 1 - for blkif in self.getInstances(): - if not blkif.attached: - attached = 0 - break - return attached - - def reattached(self): - for blkif in self.getInstances(): - blkif.reattached() - - def recv_be_create(self, msg, req): - #print 'recv_be_create>' - val = unpackMsg('blkif_be_create_t', msg) - blkif = self.getInstanceByDom(val['domid']) - self.callDeferred(blkif) - - def recv_be_connect(self, msg, req): - #print 'recv_be_create>' - val = unpackMsg('blkif_be_connect_t', msg) - blkif = self.getInstanceByDom(val['domid']) - if blkif: - blkif.send_fe_interface_status_changed() - else: - pass - - def recv_be_vbd_create(self, msg, req): - #print 'recv_be_vbd_create>' - val = unpackMsg('blkif_be_vbd_create_t', msg) - blkif = self.getInstanceByDom(val['domid']) - if blkif: - blkif.send_be_vbd_grow(val['vdevice']) - else: - pass - - def recv_be_vbd_grow(self, msg, req): - #print 'recv_be_vbd_grow>' - val = unpackMsg('blkif_be_vbd_grow_t', msg) - # Check status? - if self.attached: - self.callDeferred(0) - else: - self.reattachDevice(val['domid'], val['vdevice']) - - def recv_be_driver_status_changed(self, msg, req): - val = unpackMsg('blkif_be_driver_status_changed_t', msg) - status = val['status'] - if status == BLKIF_DRIVER_STATUS_UP and not self.attached: - for blkif in self.getInstances(): - blkif.detach() - -class BlkDev(controller.Dev): - """Info record for a block device. - """ - - def __init__(self, ctrl, vdev, mode, segment): - controller.Dev.__init__(self, ctrl) - self.vdev = vdev - self.mode = mode - self.device = segment['device'] - self.start_sector = segment['start_sector'] - self.nr_sectors = segment['nr_sectors'] - self.attached = 1 - - def readonly(self): - return 'w' not in self.mode - - def sxpr(self): - val = ['blkdev', ['vdev', self.vdev], ['mode', self.mode] ] - return val - - def destroy(self): - print 'BlkDev>destroy>', self.vdev - PrettyPrint.prettyprint(self.sxpr()) - self.controller.send_be_vbd_destroy(self.vdev) - -class BlkifController(controller.Controller): - """Block device interface controller. Handles all block devices - for a domain. - """ - - def __init__(self, factory, dom): - #print 'BlkifController> dom=', dom - controller.Controller.__init__(self, factory, dom) - self.devices = {} - - self.majorTypes = [ CMSG_BLKIF_FE ] - - self.subTypes = { - CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED: - self.recv_fe_driver_status_changed, - CMSG_BLKIF_FE_INTERFACE_CONNECT : - self.recv_fe_interface_connect, - } - self.attached = 1 - self.evtchn = None - self.registerChannel() - #print 'BlkifController<', 'dom=', self.dom, 'idx=', self.idx - - def sxpr(self): - val = ['blkif', ['dom', self.dom]] - if self.evtchn: - val.append(['evtchn', - self.evtchn['port1'], - self.evtchn['port2']]) - return val - - def lostChannel(self): - print 'BlkifController>lostChannel>', 'dom=', self.dom - #self.destroyDevices() - controller.Controller.lostChannel(self) - - def getDevices(self): - return self.devices.values() - - def getDevice(self, vdev): - return self.devices.get(vdev) - - def addDevice(self, vdev, mode, segment): - if vdev in self.devices: return None - dev = BlkDev(self, vdev, mode, segment) - self.devices[vdev] = dev - return dev - - def attachDevice(self, vdev, mode, segment, recreate=0): - """Attach a device to the specified interface. - """ - #print 'BlkifController>attach_device>', self.dom, vdev, mode, segment - dev = self.addDevice(vdev, mode, segment) - if not dev: return -1 - if recreate: - d = defer.Deferred() - d.callback(self) - else: - self.send_be_vbd_create(vdev) - d = self.factory.addDeferred() - return d - - def destroy(self): - print 'BlkifController>destroy> dom=', self.dom - def cb_destroy(val): - self.send_be_destroy() - d = self.factory.addDeferred() - d.addCallback(cb_destroy) - self.send_be_disconnect() - #self.destroyDevices() - - def destroyDevices(self): - for dev in self.getDevices(): - dev.destroy() - - def detach(self): - """Detach all devices, when the back-end control domain has changed. - """ - self.attached = 0 - for dev in self.devices.values(): - dev.attached = 0 - self.send_be_vbd_create(vdev) - - def reattachDevice(self, vdev): - """Reattach a device, when the back-end control domain has changed. - """ - dev = self.devices[vdev] - dev.attached = 1 - attached = 1 - for dev in self.devices.values(): - if not dev.attached: - attached = 0 - break - self.attached = attached - return self.attached - - def reattached(self): - """All devices have been reattached after the back-end control - domain has changed. - """ - msg = packMsg('blkif_fe_interface_status_changed_t', - { 'handle' : 0, - 'status' : BLKIF_INTERFACE_STATUS_DISCONNECTED}) - self.writeRequest(msg) - - def recv_fe_driver_status_changed(self, msg, req): - msg = packMsg('blkif_fe_interface_status_changed_t', - { 'handle' : 0, - 'status' : BLKIF_INTERFACE_STATUS_DISCONNECTED, - 'evtchn' : 0 }) - self.writeRequest(msg) - - def recv_fe_interface_connect(self, msg, req): - val = unpackMsg('blkif_fe_interface_connect_t', msg) - self.evtchn = channel.eventChannel(0, self.dom) - print 'recv_fe_interface_connect>' - PrettyPrint.prettyprint(self.sxpr()) - msg = packMsg('blkif_be_connect_t', - { 'domid' : self.dom, - 'blkif_handle' : val['handle'], - 'evtchn' : self.evtchn['port1'], - 'shmem_frame' : val['shmem_frame'] }) - self.factory.writeRequest(msg) - pass - - #def recv_fe_interface_status_changed(self, msg, req): - # (hnd, status, chan) = unpackMsg('blkif_fe_interface_status_changed_t', msg) - # print 'recv_fe_interface_status_changed>', hnd, status, chan - # pass - - def send_fe_interface_status_changed(self): - msg = packMsg('blkif_fe_interface_status_changed_t', - { 'handle' : 0, - 'status' : BLKIF_INTERFACE_STATUS_CONNECTED, - 'evtchn' : self.evtchn['port2'] }) - self.writeRequest(msg) - - def send_be_create(self): - msg = packMsg('blkif_be_create_t', - { 'domid' : self.dom, - 'blkif_handle' : 0 }) - self.factory.writeRequest(msg) - - def send_be_disconnect(self): - print '>BlkifController>send_be_disconnect>', 'dom=', self.dom - msg = packMsg('blkif_be_disconnect_t', - { 'domid' : self.dom, - 'blkif_handle' : 0 }) - self.factory.writeRequest(msg) - - def send_be_destroy(self): - print '>BlkifController>send_be_destroy>', 'dom=', self.dom - msg = packMsg('blkif_be_destroy_t', - { 'domid' : self.dom, - 'blkif_handle' : 0 }) - self.factory.writeRequest(msg) - - def send_be_vbd_create(self, vdev): - dev = self.devices[vdev] - msg = packMsg('blkif_be_vbd_create_t', - { 'domid' : self.dom, - 'blkif_handle' : 0, - 'vdevice' : dev.vdev, - 'readonly' : dev.readonly() }) - self.factory.writeRequest(msg) - - def send_be_vbd_grow(self, vdev): - dev = self.devices[vdev] - msg = packMsg('blkif_be_vbd_grow_t', - { 'domid' : self.dom, - 'blkif_handle' : 0, - 'vdevice' : dev.vdev, - 'extent.device' : dev.device, - 'extent.sector_start' : dev.start_sector, - 'extent.sector_length' : dev.nr_sectors }) - self.factory.writeRequest(msg) - - def send_be_vbd_destroy(self, vdev): - print '>BlkifController>send_be_vbd_destroy>', 'dom=', self.dom, 'vdev=', vdev - PrettyPrint.prettyprint(self.sxpr()) - dev = self.devices[vdev] - msg = packMsg('blkif_be_vbd_destroy_t', - { 'domid' : self.dom, - 'blkif_handle' : 0, - 'vdevice' : dev.vdev }) - del self.devices[vdev] - self.factory.writeRequest(msg) - diff --git a/tools/xen/lib/xend/server/channel.py b/tools/xen/lib/xend/server/channel.py deleted file mode 100755 index be98a37fd5..0000000000 --- a/tools/xen/lib/xend/server/channel.py +++ /dev/null @@ -1,378 +0,0 @@ -import xen.ext.xc; xc = xen.ext.xc.new() -from xen.ext import xu -from messages import msgTypeName - -VIRQ_MISDIRECT = 0 # Catch-all interrupt for unbound VIRQs. -VIRQ_TIMER = 1 # Timebase update, and/or requested timeout. -VIRQ_DEBUG = 2 # Request guest to dump debug info. -VIRQ_CONSOLE = 3 # (DOM0) bytes received on emergency console. -VIRQ_DOM_EXC = 4 # (DOM0) Exceptional event for some domain. - -def eventChannel(dom1, dom2): - return xc.evtchn_bind_interdomain(dom1=dom1, dom2=dom2) - -class ChannelFactory: - """Factory for creating channels. - Maintains a table of channels. - """ - - """ Channels indexed by index. """ - channels = {} - - def __init__(self): - """Constructor - do not use. Use the channelFactory function.""" - self.notifier = xu.notifier() - - def addChannel(self, channel): - """Add a channel. - """ - idx = channel.idx - self.channels[idx] = channel - self.notifier.bind(idx) - # Try to wake it up - #self.notifier.unmask(idx) - #channel.notify() - - def getChannel(self, idx): - """Get the channel with the given index (if any). - """ - return self.channels.get(idx) - - def delChannel(self, idx): - """Remove the channel with the given index (if any). - """ - if idx in self.channels: - del self.channels[idx] - self.notifier.unbind(idx) - - def domChannel(self, dom): - """Get the channel for the given domain. - Construct if necessary. - """ - dom = int(dom) - for chan in self.channels.values(): - if not isinstance(chan, Channel): continue - if chan.dom == dom: - return chan - chan = Channel(self, dom) - self.addChannel(chan) - return chan - - def virqChannel(self, virq): - """Get the channel for the given virq. - Construct if necessary. - """ - for chan in self.channels.values(): - if not isinstance(chan, VirqChannel): continue - if chan.virq == virq: - return chan - chan = VirqChannel(self, virq) - self.addChannel(chan) - return chan - - def channelClosed(self, channel): - """The given channel has been closed - remove it. - """ - self.delChannel(channel.idx) - - def createPort(self, dom): - """Create a port for a channel to the given domain. - """ - return xu.port(dom) - -def channelFactory(): - """Singleton constructor for the channel factory. - Use this instead of the class constructor. - """ - global inst - try: - inst - except: - inst = ChannelFactory() - return inst - -class BaseChannel: - """Abstract superclass for channels. - - The subclass constructor must set idx to the port to use. - """ - - def __init__(self, factory): - self.factory = factory - self.idx = -1 - self.closed = 0 - - def getIndex(self): - """Get the channel index. - """ - return self.idx - - def notificationReceived(self, type): - """Called when a notification is received. - Closes the channel on error, otherwise calls - handleNotification(type), which should be defined - in a subclass. - """ - #print 'notificationReceived> type=', type, self - if self.closed: return - if type == self.factory.notifier.EXCEPTION: - print 'notificationReceived> EXCEPTION' - info = xc.evtchn_status(self.idx) - if info['status'] == 'unbound': - print 'notificationReceived> EXCEPTION closing...' - self.close() - return - self.handleNotification(type) - - def close(self): - """Close the channel. Calls channelClosed() on the factory. - Override in subclass. - """ - self.factory.channelClosed(self) - - def handleNotification(self, type): - """Handle notification. - Define in subclass. - """ - pass - - -class VirqChannel(BaseChannel): - """A channel for handling a virq. - """ - - def __init__(self, factory, virq): - """Create a channel for the given virq using the given factory. - - Do not call directly, use virqChannel on the factory. - """ - BaseChannel.__init__(self, factory) - self.virq = virq - # Notification port (int). - self.port = xc.evtchn_bind_virq(virq) - self.idx = self.port - # Clients to call when a virq arrives. - self.clients = [] - - def __repr__(self): - return ('' - % (self.virq, self.port)) - - def getVirq(self): - """Get the channel's virq. - """ - return self.virq - - def close(self): - """Close the channel. Calls lostChannel(self) on all its clients and - channelClosed() on the factory. - """ - for c in self.clients: - c.lostChannel(self) - del self.clients - BaseChannel.close(self) - - def registerClient(self, client): - """Register a client. The client will be called with - client.virqReceived(virq) when a virq is received. - The client will be called with client.lostChannel(self) if the - channel is closed. - """ - self.clients.append(client) - - def handleNotification(self, type): - for c in self.clients: - c.virqReceived(self.virq) - - def notify(self): - xc.evtchn_send(self.port) - - -class Channel(BaseChannel): - """A control channel to a domain. Messages for the domain device controllers - are multiplexed over the channel (console, block devs, net devs). - """ - - def __init__(self, factory, dom): - """Create a channel to the given domain using the given factory. - - Do not call directly, use domChannel on the factory. - """ - BaseChannel.__init__(self, factory) - # Domain. - self.dom = int(dom) - # Domain port (object). - self.port = self.factory.createPort(dom) - # Channel port (int). - self.idx = self.port.local_port - # Registered devices. - self.devs = [] - # Devices indexed by the message types they handle. - self.devs_by_type = {} - # Output queue. - self.queue = [] - self.closed = 0 - - def getLocalPort(self): - """Get the local port. - """ - return self.port.local_port - - def getRemotePort(self): - """Get the remote port. - """ - return self.port.remote_port - - def close(self): - """Close the channel. Calls lostChannel() on all its devices and - channelClosed() on the factory. - """ - self.closed = 1 - for d in self.devs: - d.lostChannel() - self.factory.channelClosed(self) - self.devs = [] - self.devs_by_type = {} - - def registerDevice(self, types, dev): - """Register a device controller. - - @param types message types the controller handles - @param dev device controller - """ - if self.closed: return - self.devs.append(dev) - for ty in types: - self.devs_by_type[ty] = dev - - def deregisterDevice(self, dev): - """Remove the registration for a device controller. - - @param dev device controller - """ - if dev in self.devs: - self.devs.remove(dev) - types = [ ty for (ty, d) in self.devs_by_type.items() if d == dev ] - for ty in types: - del self.devs_by_type[ty] - - def getDevice(self, type): - """Get the device controller handling a message type. - - @param type message type - @returns controller or None - """ - return self.devs_by_type.get(type) - - def getMessageType(self, msg): - """Get a 2-tuple of the message type and subtype. - """ - hdr = msg.get_header() - return (hdr['type'], hdr.get('subtype')) - - def __repr__(self): - return ('' - % (self.dom, - self.port.local_port, - self.port.remote_port)) - - def handleNotification(self, type): - work = 0 - work += self.handleRequests() - work += self.handleResponses() - work += self.handleWrites() - if work: - self.notify() - - def notify(self): - self.port.notify() - - def handleRequests(self): - work = 0 - while 1: - msg = self.readRequest() - if not msg: break - self.requestReceived(msg) - work += 1 - return work - - def requestReceived(self, msg): - (ty, subty) = self.getMessageType(msg) - #todo: Must respond before writing any more messages. - #todo: Should automate this (respond on write) - self.port.write_response(msg) - dev = self.getDevice(ty) - if dev: - dev.requestReceived(msg, ty, subty) - else: - print ("requestReceived> No device: Message type %s %d:%d" - % (msgTypeName(ty, subty), ty, subty)), self - - def handleResponses(self): - work = 0 - while 1: - msg = self.readResponse() - if not msg: break - self.responseReceived(msg) - work += 1 - return work - - def responseReceived(self, msg): - (ty, subty) = self.getMessageType(msg) - dev = self.getDevice(ty) - if dev: - dev.responseReceived(msg, ty, subty) - else: - print ("responseReceived> No device: Message type %d:%d" - % (msgTypeName(ty, subty), ty, subty)), self - - def handleWrites(self): - work = 0 - # Pull data from producers. - for dev in self.devs: - work += dev.produceRequests() - # Flush the queue. - while self.queue and self.port.space_to_write_request(): - msg = self.queue.pop(0) - self.port.write_request(msg) - work += 1 - return work - - def writeRequest(self, msg, notify=1): - if self.closed: - val = -1 - elif self.writeReady(): - self.port.write_request(msg) - if notify: self.notify() - val = 1 - else: - self.queue.append(msg) - val = 0 - return val - - def writeResponse(self, msg): - if self.closed: return -1 - self.port.write_response(msg) - return 1 - - def writeReady(self): - if self.closed or self.queue: return 0 - return self.port.space_to_write_request() - - def readRequest(self): - if self.closed: - return None - if self.port.request_to_read(): - val = self.port.read_request() - else: - val = None - return val - - def readResponse(self): - if self.closed: - return None - if self.port.response_to_read(): - val = self.port.read_response() - else: - val = None - return val diff --git a/tools/xen/lib/xend/server/console.py b/tools/xen/lib/xend/server/console.py deleted file mode 100755 index ab8b22e41e..0000000000 --- a/tools/xen/lib/xend/server/console.py +++ /dev/null @@ -1,232 +0,0 @@ - -from twisted.internet import reactor -from twisted.internet import protocol -from twisted.protocols import telnet - -from xen.ext import xu - -from xen.xend import EventServer -eserver = EventServer.instance() - -import controller -from messages import * -from params import * - -"""Telnet binary option.""" -TRANSMIT_BINARY = '0' -WILL = chr(251) -IAC = chr(255) - -class ConsoleProtocol(protocol.Protocol): - """Asynchronous handler for a console TCP socket. - """ - - def __init__(self, controller, idx): - self.controller = controller - self.idx = idx - self.addr = None - self.binary = 0 - - def connectionMade(self): - peer = self.transport.getPeer() - self.addr = (peer.host, peer.port) - if self.controller.connect(self.addr, self): - self.transport.write("Cannot connect to console %d on domain %d\n" - % (self.idx, self.controller.dom)) - self.loseConnection() - return - else: - # KAF: A nice quiet successful connect. Don't bother with telnet - # control sequence -- telnet is not the appropriate protocol here. - #self.transport.write("Connected to console %d on domain %d\n" - # % (self.idx, self.controller.dom)) - #self.setTelnetTransmitBinary() - eserver.inject('xend.console.connect', - [self.idx, self.addr[0], self.addr[1]]) - - def setTelnetTransmitBinary(self): - """Send the sequence to set the telnet TRANSMIT-BINARY option. - """ - self.write(IAC + WILL + TRANSMIT_BINARY) - - def dataReceived(self, data): - if self.controller.handleInput(self, data): - self.loseConnection() - - def write(self, data): - #if not self.connected: return -1 - self.transport.write(data) - return len(data) - - def connectionLost(self, reason=None): - eserver.inject('xend.console.disconnect', - [self.idx, self.addr[0], self.addr[1]]) - self.controller.disconnect() - - def loseConnection(self): - self.transport.loseConnection() - -class ConsoleFactory(protocol.ServerFactory): - """Asynchronous handler for a console server socket. - """ - protocol = ConsoleProtocol - - def __init__(self, controller, idx): - #protocol.ServerFactory.__init__(self) - self.controller = controller - self.idx = idx - - def buildProtocol(self, addr): - proto = self.protocol(self.controller, self.idx) - proto.factory = self - return proto - -class ConsoleControllerFactory(controller.ControllerFactory): - """Factory for creating console controllers. - """ - - def createInstance(self, dom, console_port=None): - if console_port is None: - console_port = CONSOLE_PORT_BASE + dom - console = ConsoleController(self, dom, console_port) - self.addInstance(console) - eserver.inject('xend.console.create', - [console.idx, console.dom, console.console_port]) - return console - - def consoleClosed(self, console): - eserver.inject('xend.console.close', console.idx) - self.delInstance(console) - -class ConsoleController(controller.Controller): - """Console controller for a domain. - Does not poll for i/o itself, but relies on the notifier to post console - output and the connected TCP sockets to post console input. - """ - - def __init__(self, factory, dom, console_port): - #print 'ConsoleController> dom=', dom, type(dom) - controller.Controller.__init__(self, factory, dom) - self.majorTypes = [ CMSG_CONSOLE ] - self.status = "new" - self.addr = None - self.conn = None - self.rbuf = xu.buffer() - self.wbuf = xu.buffer() - self.console_port = console_port - - self.registerChannel() - self.listener = None - self.listen() - #print 'ConsoleController<', 'dom=', self.dom, 'idx=', self.idx - - def sxpr(self): - val =['console', - ['status', self.status ], - ['id', self.idx ], - ['domain', self.dom ], - ['local_port', self.channel.getLocalPort() ], - ['remote_port', self.channel.getRemotePort() ], - ['console_port', self.console_port ] ] - if self.addr: - val.append(['connected', self.addr[0], self.addr[1]]) - return val - - def ready(self): - return not (self.closed() or self.rbuf.empty()) - - def closed(self): - return self.status == 'closed' - - def connected(self): - return self.status == 'connected' - - def close(self): - try: - #print 'ConsoleController> close dom=', self.dom - self.status = "closed" - if self.conn: - self.conn.loseConnection() - self.listener.stopListening() - self.deregisterChannel() - self.lostChannel() - except Exception, ex: - print 'ConsoleController>close>', ex - raise - - def listen(self): - """Listen for TCP connections to the console port.. - """ - if self.closed(): return - self.status = "listening" - if self.listener: - #self.listener.startListening() - pass - else: - f = ConsoleFactory(self, self.idx) - self.listener = reactor.listenTCP(self.console_port, f) - - def connect(self, addr, conn): - if self.closed(): return -1 - if self.connected(): return -1 - self.addr = addr - self.conn = conn - self.status = "connected" - self.handleOutput() - return 0 - - def disconnect(self): - if self.conn: - self.conn.loseConnection() - self.addr = None - self.conn = None - self.listen() - - def requestReceived(self, msg, type, subtype): - #print '***Console', self.dom, msg.get_payload() - self.rbuf.write(msg.get_payload()) - self.handleOutput() - - def responseReceived(self, msg, type, subtype): - pass - - def produceRequests(self): - # Send as much pending console data as there is room for. - work = 0 - while not self.wbuf.empty() and self.channel.writeReady(): - msg = xu.message(CMSG_CONSOLE, 0, 0) - msg.append_payload(self.wbuf.read(msg.MAX_PAYLOAD)) - work += self.channel.writeRequest(msg, notify=0) - return work - - def handleInput(self, conn, data): - """Handle some external input aimed at the console. - Called from a TCP connection (conn). - """ - if self.closed(): return -1 - if conn != self.conn: return 0 - self.wbuf.write(data) - if self.produceRequests(): - self.channel.notify() - return 0 - - def handleOutput(self): - """Handle buffered output from the console. - Sends it to the connected console (if any). - """ - if self.closed(): - #print 'Console>handleOutput> closed' - return -1 - if not self.conn: - #print 'Console>handleOutput> not connected' - return 0 - while not self.rbuf.empty(): - try: - #print 'Console>handleOutput> writing...' - bytes = self.conn.write(self.rbuf.peek()) - if bytes > 0: - self.rbuf.discard(bytes) - except socket.error, error: - pass - #print 'Console>handleOutput<' - return 0 diff --git a/tools/xen/lib/xend/server/controller.py b/tools/xen/lib/xend/server/controller.py deleted file mode 100755 index 900c2d55b0..0000000000 --- a/tools/xen/lib/xend/server/controller.py +++ /dev/null @@ -1,169 +0,0 @@ -from twisted.internet import defer - -import channel -from messages import msgTypeName - -class CtrlMsgRcvr: - """Abstract class for things that deal with a control interface to a domain. - """ - - - def __init__(self): - self.channelFactory = channel.channelFactory() - self.majorTypes = [ ] - self.subTypes = {} - self.dom = None - self.channel = None - self.idx = None - - def requestReceived(self, msg, type, subtype): - method = self.subTypes.get(subtype) - if method: - method(msg, 1) - else: - print ('requestReceived> No handler: Message type %s %d:%d' - % (msgTypeName(type, subtype), type, subtype)), self - - def responseReceived(self, msg, type, subtype): - method = self.subTypes.get(subtype) - if method: - method(msg, 0) - else: - print ('responseReceived> No handler: Message type %s %d:%d' - % (msgTypeName(type, subtype), type, subtype)), self - - def lostChannel(self): - pass - - def registerChannel(self): - #print 'CtrlMsgRcvr>registerChannel>', self - self.channel = self.channelFactory.domChannel(self.dom) - self.idx = self.channel.getIndex() - if self.majorTypes: - self.channel.registerDevice(self.majorTypes, self) - - def deregisterChannel(self): - #print 'CtrlMsgRcvr>deregisterChannel>', self - if self.channel: - self.channel.deregisterDevice(self) - del self.channel - - def produceRequests(self): - return 0 - - def writeRequest(self, msg): - if self.channel: - self.channel.writeRequest(msg) - else: - print 'CtrlMsgRcvr>writeRequest>', 'no channel!', self - - def writeResponse(self, msg): - if self.channel: - self.channel.writeResponse(msg) - else: - print 'CtrlMsgRcvr>writeResponse>', 'no channel!', self - -class ControllerFactory(CtrlMsgRcvr): - """Abstract class for factories creating controllers. - Maintains a table of instances. - """ - - def __init__(self): - CtrlMsgRcvr.__init__(self) - self.instances = {} - self.dlist = [] - self.dom = 0 - # Timeout (in seconds) for deferreds. - self.timeout = 10 - - def addInstance(self, instance): - self.instances[instance.idx] = instance - - def getInstance(self, idx): - return self.instances.get(idx) - - def getInstances(self): - return self.instances.values() - - def getInstanceByDom(self, dom): - for inst in self.instances.values(): - if inst.dom == dom: - return inst - return None - - def delInstance(self, instance): - #print 'ControllerFactory>delInstance>', instance.idx - if instance.idx in self.instances: - #print 'ControllerFactory>delInstance> remove', instance.idx - del self.instances[instance.idx] - - def createInstance(self, dom, recreate=0): - raise NotImplementedError() - - def instanceClosed(self, instance): - #print 'ControllerFactory>instanceClosed>', instance.idx, instance - self.delInstance(instance) - - def addDeferred(self): - d = defer.Deferred() - if self.timeout > 0: - # The deferred will error if not called before timeout. - d.setTimeout(self.timeout) - self.dlist.append(d) - return d - - def callDeferred(self, *args): - if self.dlist: - d = self.dlist.pop(0) - d.callback(*args) - - def errDeferred(self, *args): - if self.dlist: - d = self.dlist.pop(0) - d.errback(*args) - -class Controller(CtrlMsgRcvr): - """Abstract class for a device controller attached to a domain. - """ - - def __init__(self, factory, dom): - CtrlMsgRcvr.__init__(self) - self.factory = factory - self.dom = int(dom) - self.channel = None - self.idx = None - - def close(self): - self.deregisterChannel() - self.lostChannel() - - def lostChannel(self): - #print 'Controller>lostChannel>', self, self.factory - self.factory.instanceClosed(self) - -class Dev: - - def __init__(self, controller): - self.controller = controller - self.props = {} - - def setprop(self, k, v): - self.props[k] = v - - def getprop(self, k, v=None): - return self.props.get(k, v) - - def hasprop(self, k): - return k in self.props - - def delprop(self, k): - if k in self.props: - del self.props[k] - - #def __repr__(self): - # return str(self.sxpr()) - - def sxpr(self): - raise NotImplementedError() - - diff --git a/tools/xen/lib/xend/server/cstruct.py b/tools/xen/lib/xend/server/cstruct.py deleted file mode 100755 index 880931b41f..0000000000 --- a/tools/xen/lib/xend/server/cstruct.py +++ /dev/null @@ -1,269 +0,0 @@ -import struct - -class Struct: - - maxDepth = 10 - - base = ['x', 'B', 'H', 'I', 'L', 'Q', 'c', 'h', 'i', 'l', 'q', ] - - sizes = {'B': 1, - 'H': 2, - 'I': 4, - 'L': 4, - 'Q': 8, - 'c': 1, - 'h': 2, - 'i': 4, - 'l': 4, - 'q': 8, - 'x': 1, - } - - formats = { - 'int8' : 'B', - 'int16' : 'H', - 'int32' : 'I', - 'int64' : 'Q', - 'u8' : 'B', - 'u16' : 'H', - 'u32' : 'I', - 'u64' : 'Q' - } - - def typedef(self, name, val): - self.formats[name] = val - - def struct(self, name, *f): - self.typedef(name, StructInfo(self, f)) - - def getType(self, name): - return self.formats[name] - - def format(self, ty): - d = 0 - f = ty - while d < self.maxDepth: - d += 1 - f = self.formats[f] - if isinstance(f, StructInfo): - return f.format() - if f in self.base: - return f - return -1 - - def alignedformat(self, ty): - fmt = self.format(ty) - #print 'alignedformat> %s |%s|' %(ty, fmt) - afmt = self.align(fmt) - #print 'alignedformat< %s |%s| |%s|' % (ty, fmt, afmt) - return afmt - - def align(self, fmt): - n1 = 0 - afmt = '' - for a in fmt: - n2 = self.getSize(a) - m = n1 % n2 - if m: - d = (n2 - m) - afmt += 'x' * d - n1 += d - afmt += a - n1 += n2 - return afmt - - def fmtsize(self, fmt): - s = 0 - for f in fmt: - s += self.getSize(f) - return s - - def getSize(self, f): - return self.sizes[f] - - def pack(self, ty, data): - return self.getType(ty).pack(data) - - def unpack(self, ty, data): - return self.getType(ty).unpack(data) - - def show(self): - l = self.formats.keys() - l.sort() - for v in l: - print "%-35s %-10s %s" % (v, self.format(v), self.alignedformat(v)) - - -class StructInfo: - - def __init__(self, s, f): - self.fmt = None - self.structs = s - self.fields = f - - def alignedformat(self): - if self.afmt: return self.afmt - self.afmt = self.structs.align(self.format()) - return self.afmt - - def format(self): - if self.fmt: return self.fmt - fmt = "" - for (ty, name) in self.fields: - fmt += self.formatString(ty) - self.fmt = fmt - return fmt - - def formatString(self, ty): - if ty in self.fields: - ty = self.fields[ty] - return self.structs.format(ty) - - def pack(self, *args): - return struct.pack(self.alignedformat(), *args) - - def unpack(self, data): - return struct.unpack(self.alignedformat(), data) - -types = Struct() - -types.typedef('short' , 'h') -types.typedef('int' , 'i') -types.typedef('long' , 'l') -types.typedef('unsigned short', 'H') -types.typedef('unsigned int' , 'I') -types.typedef('unsigned long' , 'L') -types.typedef('domid_t' , 'u64') -types.typedef('blkif_vdev_t' , 'u16') -types.typedef('blkif_pdev_t' , 'u16') -types.typedef('blkif_sector_t', 'u64') - -types.struct('u8[6]', - ('u8', 'a1'), - ('u8', 'a2'), - ('u8', 'a3'), - ('u8', 'a4'), - ('u8', 'a5'), - ('u8', 'a6')) - -types.struct('blkif_fe_interface_status_changed_t', - ('unsigned int', 'handle'), - ('unsigned int', 'status'), - ('unsigned int', 'evtchn')) - -types.struct('blkif_fe_driver_status_changed_t', - ('unsigned int', 'status'), - ('unsigned int', 'nr_interfaces')) - -types.struct('blkif_fe_interface_connect_t', - ('unsigned int' , 'handle'), - ('unsigned long', 'shmem_frame')) - -types.struct('blkif_fe_interface_disconnect_t', - ('unsigned int', 'handle')) - -types.struct('blkif_extent_t', - ('blkif_pdev_t' , 'device'), - ('blkif_sector_t', 'sector_start'), - ('blkif_sector_t', 'sector_length')) - -types.struct('blkif_be_create_t', - ('domid_t' , 'domid'), - ('unsigned int', 'blkif_handle'), - ('unsigned int', 'status')) - -types.struct('blkif_be_destroy_t', - ('domid_t' , 'domid'), - ('unsigned int', 'blkif_handle'), - ('unsigned int', 'status')) - -types.struct('blkif_be_connect_t', - ('domid_t' , 'domid'), - ('unsigned int' , 'blkif_handle'), - ('unsigned int' , 'evtchn'), - ('unsigned long', 'shmem_frame'), - ('unsigned int' , 'status')) - -types.struct('blkif_be_disconnect_t', - ('domid_t' , 'domid'), - ('unsigned int', 'blkif_handle'), - ('unsigned int', 'status')) - -types.struct('blkif_be_vbd_create_t', - ('domid_t' , 'domid'), #Q - ('unsigned int', 'blkif_handle'), #I - ('blkif_vdev_t', 'vdevice'), #H - ('int' , 'readonly'), #i - ('unsigned int', 'status')) #I - -types.struct('blkif_be_vbd_destroy_t', - ('domid_t' , 'domid'), - ('unsigned int', 'blkif_handle'), - ('blkif_vdev_t', 'vdevice'), - ('unsigned int', 'status')) - -types.struct('blkif_be_vbd_grow_t', - ('domid_t' , 'domid'), #Q - ('unsigned int' , 'blkif_handle'), #I - ('blkif_vdev_t' , 'vdevice'), #H - ('blkif_extent_t', 'extent'), #HQQ - ('unsigned int' , 'status')) #I - -types.struct('blkif_be_vbd_shrink_t', - ('domid_t' , 'domid'), - ('unsigned int', 'blkif_handle'), - ('blkif_vdev_t', 'vdevice'), - ('unsigned int', 'status')) - -types.struct('blkif_be_driver_status_changed_t', - ('unsigned int', 'status'), - ('unsigned int', 'nr_interfaces')) - -types.struct('netif_fe_interface_status_changed_t', - ('unsigned int', 'handle'), - ('unsigned int', 'status'), - ('unsigned int', 'evtchn'), - ('u8[6]', 'mac')) - -types.struct('netif_fe_driver_status_changed_t', - ('unsigned int', 'status'), - ('unsigned int', 'nr_interfaces')) - -types.struct('netif_fe_interface_connect_t', - ('unsigned int', 'handle'), - ('unsigned long', 'tx_shmem_frame'), - ('unsigned long', 'rx_shmem_frame')) - -types.struct('netif_fe_interface_disconnect_t', - ('unsigned int', 'handle')) - -types.struct('netif_be_create_t', - ('domid_t' , 'domid'), - ('unsigned int', 'netif_handle'), - ('u8[6]' , 'mac'), - ('unsigned int', 'status')) - -types.struct('netif_be_destroy_t', - ('domid_t' , 'domid'), - ('unsigned int', 'netif_handle'), - ('unsigned int', 'status')) - -types.struct('netif_be_connect_t', - ('domid_t' , 'domid'), - ('unsigned int' , 'netif_handle'), - ('unsigned int' , 'evtchn'), - ('unsigned long', 'tx_shmem_frame'), - ('unsigned long', 'rx_shmem_frame'), - ('unsigned int' , 'status')) - -types.struct('netif_be_disconnect_t', - ('domid_t' , 'domid'), - ('unsigned int', 'netif_handle'), - ('unsigned int', 'status')) - -types.struct('netif_be_driver_status_changed_t', - ('unsigned int', 'status'), - ('unsigned int', 'nr_interfaces')) - -if 1 or __name__ == "__main__": - types.show() diff --git a/tools/xen/lib/xend/server/domain.py b/tools/xen/lib/xend/server/domain.py deleted file mode 100644 index ab22234480..0000000000 --- a/tools/xen/lib/xend/server/domain.py +++ /dev/null @@ -1,41 +0,0 @@ -import channel -import controller -from messages import * - -class DomainControllerFactory(controller.ControllerFactory): - """Factory for creating domain controllers. - """ - - def createInstance(self, dom): - d = DomainController(self, dom) - self.addInstance(d) - return d - - def getInstanceByDom(self, dom): - for inst in self.instances.values(): - if inst.dom == dom: - return inst - inst = self.createInstance(dom) - return inst - - -class DomainController(controller.Controller): - """Generic controller for a domain. - """ - - reasons = {'poweroff' : 'shutdown_poweroff_t', - 'reboot' : 'shutdown_reboot_t', - 'suspend' : 'shutdown_suspend_t' } - - def __init__(self, factory, dom): - controller.Controller.__init__(self, factory, dom) - self.majorTypes = [ CMSG_SHUTDOWN ] - self.registerChannel() - print 'DomainController>', self, self.channel, self.idx - - def shutdown(self, reason): - msgtype = self.reasons.get(reason) - if not msgtype: - raise ValueError('invalid reason:' + reason) - msg = packMsg(msgtype, {}) - self.writeRequest(msg) diff --git a/tools/xen/lib/xend/server/messages.py b/tools/xen/lib/xend/server/messages.py deleted file mode 100644 index e12d7b6e24..0000000000 --- a/tools/xen/lib/xend/server/messages.py +++ /dev/null @@ -1,219 +0,0 @@ -import struct - -from xen.ext import xu - -DEBUG = 0 - -""" All message formats. -Added to incrementally for the various message types. -See below. -""" -msg_formats = {} - -#============================================================================ -# Console message types. -#============================================================================ - -CMSG_CONSOLE = 0 - -console_formats = { 'console_data': (CMSG_CONSOLE, 0) } - -msg_formats.update(console_formats) - -#============================================================================ -# Block interface message types. -#============================================================================ - -CMSG_BLKIF_BE = 1 -CMSG_BLKIF_FE = 2 - -CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED = 0 -CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED = 32 -CMSG_BLKIF_FE_INTERFACE_CONNECT = 33 -CMSG_BLKIF_FE_INTERFACE_DISCONNECT = 34 - -CMSG_BLKIF_BE_CREATE = 0 -CMSG_BLKIF_BE_DESTROY = 1 -CMSG_BLKIF_BE_CONNECT = 2 -CMSG_BLKIF_BE_DISCONNECT = 3 -CMSG_BLKIF_BE_VBD_CREATE = 4 -CMSG_BLKIF_BE_VBD_DESTROY = 5 -CMSG_BLKIF_BE_VBD_GROW = 6 -CMSG_BLKIF_BE_VBD_SHRINK = 7 -CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED = 32 - -BLKIF_DRIVER_STATUS_DOWN = 0 -BLKIF_DRIVER_STATUS_UP = 1 - -BLKIF_INTERFACE_STATUS_DESTROYED = 0 #/* Interface doesn't exist. */ -BLKIF_INTERFACE_STATUS_DISCONNECTED = 1 #/* Exists but is disconnected. */ -BLKIF_INTERFACE_STATUS_CONNECTED = 2 #/* Exists and is connected. */ - -BLKIF_BE_STATUS_OKAY = 0 -BLKIF_BE_STATUS_ERROR = 1 -BLKIF_BE_STATUS_INTERFACE_EXISTS = 2 -BLKIF_BE_STATUS_INTERFACE_NOT_FOUND = 3 -BLKIF_BE_STATUS_INTERFACE_CONNECTED = 4 -BLKIF_BE_STATUS_VBD_EXISTS = 5 -BLKIF_BE_STATUS_VBD_NOT_FOUND = 6 -BLKIF_BE_STATUS_OUT_OF_MEMORY = 7 -BLKIF_BE_STATUS_EXTENT_NOT_FOUND = 8 -BLKIF_BE_STATUS_MAPPING_ERROR = 9 - -blkif_formats = { - 'blkif_be_connect_t': - (CMSG_BLKIF_BE, CMSG_BLKIF_BE_CONNECT), - - 'blkif_be_create_t': - (CMSG_BLKIF_BE, CMSG_BLKIF_BE_CREATE), - - 'blkif_be_disconnect_t': - (CMSG_BLKIF_BE, CMSG_BLKIF_BE_DISCONNECT), - - 'blkif_be_destroy_t': - (CMSG_BLKIF_BE, CMSG_BLKIF_BE_DESTROY), - - 'blkif_be_vbd_create_t': - (CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_CREATE), - - 'blkif_be_vbd_grow_t': - (CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_GROW), - - 'blkif_be_vbd_destroy_t': - (CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_DESTROY), - - 'blkif_fe_interface_status_changed_t': - (CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED), - - 'blkif_fe_driver_status_changed_t': - (CMSG_BLKIF_FE, CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED), - - 'blkif_fe_interface_connect_t': - (CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_CONNECT), -} - -msg_formats.update(blkif_formats) - -#============================================================================ -# Network interface message types. -#============================================================================ - -CMSG_NETIF_BE = 3 -CMSG_NETIF_FE = 4 - -CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED = 0 -CMSG_NETIF_FE_DRIVER_STATUS_CHANGED = 32 -CMSG_NETIF_FE_INTERFACE_CONNECT = 33 -CMSG_NETIF_FE_INTERFACE_DISCONNECT = 34 - -CMSG_NETIF_BE_CREATE = 0 -CMSG_NETIF_BE_DESTROY = 1 -CMSG_NETIF_BE_CONNECT = 2 -CMSG_NETIF_BE_DISCONNECT = 3 -CMSG_NETIF_BE_DRIVER_STATUS_CHANGED = 32 - -NETIF_INTERFACE_STATUS_DESTROYED = 0 #/* Interface doesn't exist. */ -NETIF_INTERFACE_STATUS_DISCONNECTED = 1 #/* Exists but is disconnected. */ -NETIF_INTERFACE_STATUS_CONNECTED = 2 #/* Exists and is connected. */ - -NETIF_DRIVER_STATUS_DOWN = 0 -NETIF_DRIVER_STATUS_UP = 1 - -netif_formats = { - 'netif_be_connect_t': - (CMSG_NETIF_BE, CMSG_NETIF_BE_CONNECT), - - 'netif_be_create_t': - (CMSG_NETIF_BE, CMSG_NETIF_BE_CREATE), - - 'netif_be_disconnect_t': - (CMSG_NETIF_BE, CMSG_NETIF_BE_DISCONNECT), - - 'netif_be_destroy_t': - (CMSG_NETIF_BE, CMSG_NETIF_BE_DESTROY), - - 'netif_be_driver_status_changed_t': - (CMSG_NETIF_BE, CMSG_NETIF_BE_DRIVER_STATUS_CHANGED), - - 'netif_fe_driver_status_changed_t': - (CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED), - - 'netif_fe_interface_connect_t': - (CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_CONNECT), - - 'netif_fe_interface_status_changed_t': - (CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED), - } - -msg_formats.update(netif_formats) - -#============================================================================ -CMSG_SHUTDOWN = 6 - -CMSG_SHUTDOWN_POWEROFF = 0 -CMSG_SHUTDOWN_REBOOT = 1 -CMSG_SHUTDOWN_SUSPEND = 2 - -STOPCODE_shutdown = 0 -STOPCODE_reboot = 1 -STOPCODE_suspend = 2 - -shutdown_formats = { - 'shutdown_poweroff_t': - (CMSG_SHUTDOWN, CMSG_SHUTDOWN_POWEROFF), - - 'shutdown_reboot_t': - (CMSG_SHUTDOWN, CMSG_SHUTDOWN_REBOOT), - - 'shutdown_suspend_t': - (CMSG_SHUTDOWN, CMSG_SHUTDOWN_SUSPEND), - } - -msg_formats.update(shutdown_formats) - -#============================================================================ - -class Msg: - pass - -def packMsg(ty, params): - if DEBUG: print '>packMsg', ty, params - (major, minor) = msg_formats[ty] - args = {} - for (k, v) in params.items(): - if k == 'mac': - for i in range(0, 6): - args['mac[%d]' % i] = v[i] - else: - args[k] = v - if DEBUG: - for (k, v) in args.items(): - print 'packMsg>', k, v, type(v) - msgid = 0 - msg = xu.message(major, minor, msgid, args) - return msg - -def unpackMsg(ty, msg): - args = msg.get_payload() - mac = [0, 0, 0, 0, 0, 0] - macs = [] - for (k, v) in args.items(): - if k.startswith('mac['): - macs += k - i = int(k[4:5]) - mac[i] = v - else: - pass - if macs: - args['mac'] = mac - for k in macs: - del args[k] - if DEBUG: print 'createInstance> dom=', dom - netif = self.getInstanceByDom(dom) - if netif is None: - netif = NetifController(self, dom) - self.addInstance(netif) - return netif - - def getDomainDevices(self, dom): - netif = self.getInstanceByDom(dom) - return (netif and netif.getDevices()) or [] - - def getDomainDevice(self, dom, vif): - netif = self.getInstanceByDom(dom) - return (netif and netif.getDevice(vif)) or None - - def setControlDomain(self, dom, recreate=0): - """Set the 'back-end' device driver domain. - """ - if self.dom == dom: return - self.deregisterChannel() - if not recreate: - self.attached = 0 - self.dom = dom - self.registerChannel() - # - #if xend.netif.be_port.remote_dom != 0: - # xend.netif.recovery = True - # xend.netif.be_port = xend.main.port_from_dom(dom) - # - - def getControlDomain(self): - return self.dom - - def recv_be_create(self, msg, req): - self.callDeferred(0) - - def recv_be_connect(self, msg, req): - val = unpackMsg('netif_be_connect_t', msg) - dom = val['domid'] - vif = val['netif_handle'] - netif = self.getInstanceByDom(dom) - if netif: - netif.send_interface_connected(vif) - else: - print "recv_be_connect> unknown vif=", vif - pass - - def recv_be_driver_status_changed(self, msg, req): - val = unpackMsg('netif_be_driver_status_changed_t', msg) - status = val['status'] - if status == NETIF_DRIVER_STATUS_UP and not self.attached: - # If we are not attached the driver domain was changed, and - # this signals the new driver domain is ready. - for netif in self.getInstances(): - netif.reattach_devices() - self.attached = 1 - -## pl = msg.get_payload() -## status = pl['status'] -## if status == NETIF_DRIVER_STATUS_UP: -## if xend.netif.recovery: -## print "New netif backend now UP, notifying guests:" -## for netif_key in interface.list.keys(): -## netif = interface.list[netif_key] -## netif.create() -## print " Notifying %d" % netif.dom -## msg = xu.message( -## CMSG_NETIF_FE, -## CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED, 0, -## { 'handle' : 0, 'status' : 1 }) -## netif.ctrlif_tx_req(xend.main.port_from_dom(netif.dom),msg) -## print "Done notifying guests" -## recovery = False - -class NetDev(controller.Dev): - """Info record for a network device. - """ - - def __init__(self, ctrl, vif, mac): - controller.Dev.__init__(self, ctrl) - self.vif = vif - self.mac = mac - self.evtchn = None - self.bridge = None - self.ipaddr = [] - - def sxpr(self): - vif = str(self.vif) - mac = self.get_mac() - val = ['netdev', ['vif', vif], ['mac', mac]] - if self.bridge: - val.append(['bridge', self.bridge]) - if self.evtchn: - val.append(['evtchn', - self.evtchn['port1'], - self.evtchn['port2']]) - return val - - def get_vifname(self): - return "vif%d.%d" % (self.controller.dom, self.vif) - - def get_mac(self): - return ':'.join(map(lambda x: "%x" % x, self.mac)) - - def vifctl_params(self): - return { 'mac' : self.get_mac(), - 'bridge': self.bridge, - 'ipaddr': self.ipaddr } - - def up(self, bridge=None, ipaddr=[]): - self.bridge = bridge - self.ipaddr = ipaddr - Vifctl.up(self.get_vifname(), **self.vifctl_params()) - - def down(self): - Vifctl.down(self.get_vifname(), **self.vifctl_params()) - - def destroy(self): - def cb_destroy(val): - self.controller.send_be_destroy(self.vif) - print 'NetDev>destroy>', 'vif=', self.vif - PrettyPrint.prettyprint(self.sxpr()) - self.down() - d = self.controller.factory.addDeferred() - d.addCallback(cb_destroy) - self.controller.send_be_disconnect(self.vif) - #self.controller.send_be_destroy(self.vif) - - -class NetifController(controller.Controller): - """Network interface controller. Handles all network devices for a domain. - """ - - def __init__(self, factory, dom): - #print 'NetifController> dom=', dom - controller.Controller.__init__(self, factory, dom) - self.devices = {} - - self.majorTypes = [ CMSG_NETIF_FE ] - - self.subTypes = { - CMSG_NETIF_FE_DRIVER_STATUS_CHANGED: - self.recv_fe_driver_status_changed, - CMSG_NETIF_FE_INTERFACE_CONNECT : - self.recv_fe_interface_connect, - } - self.registerChannel() - #print 'NetifController<', 'dom=', self.dom, 'idx=', self.idx - - def sxpr(self): - val = ['netif', ['dom', self.dom]] - return val - - def randomMAC(self): - # VIFs get a random MAC address with a "special" vendor id. - # - # NB. The vendor is currently an "obsolete" one that used to belong - # to DEC (AA-00-00). Using it is probably a bit rude :-) - # - # NB2. The first bit of the first random octet is set to zero for - # all dynamic MAC addresses. This may allow us to manually specify - # MAC addresses for some VIFs with no fear of clashes. - mac = [ 0xaa, 0x00, 0x00, - random.randint(0x00, 0x7f), - random.randint(0x00, 0xff), - random.randint(0x00, 0xff) ] - return mac - - def lostChannel(self): - print 'NetifController>lostChannel>', 'dom=', self.dom - #self.destroyDevices() - controller.Controller.lostChannel(self) - - def getDevices(self): - return self.devices.values() - - def getDevice(self, vif): - return self.devices.get(vif) - - def addDevice(self, vif, vmac): - if vmac is None: - mac = self.randomMAC() - else: - mac = [ int(x, 16) for x in vmac.split(':') ] - if len(mac) != 6: raise ValueError("invalid mac") - #print "attach_device>", "vif=", vif, "mac=", mac - dev = NetDev(self, vif, mac) - self.devices[vif] = dev - return dev - - def destroy(self): - print 'NetifController>destroy>', 'dom=', self.dom - self.destroyDevices() - - def destroyDevices(self): - for dev in self.getDevices(): - dev.destroy() - - def attachDevice(self, vif, vmac, recreate=0): - """Attach a network device. - If vmac is None a random mac address is assigned. - - @param vif interface index - @param vmac mac address (string) - """ - self.addDevice(vif, vmac) - if recreate: - d = defer.Deferred() - d.callback(self) - else: - d = self.factory.addDeferred() - self.send_be_create(vif) - return d - - def reattach_devices(self): - """Reattach all devices when the back-end control domain has changed. - """ - d = self.factory.addDeferred() - self.send_be_create(vif) - self.attach_fe_devices(0) - - def attach_fe_devices(self): - for dev in self.devices.values(): - msg = packMsg('netif_fe_interface_status_changed_t', - { 'handle' : dev.vif, - 'status' : NETIF_INTERFACE_STATUS_DISCONNECTED, - 'evtchn' : 0, - 'mac' : dev.mac }) - self.writeRequest(msg) - - def recv_fe_driver_status_changed(self, msg, req): - if not req: return - msg = packMsg('netif_fe_driver_status_changed_t', - { 'status' : NETIF_DRIVER_STATUS_UP, - 'nr_interfaces' : len(self.devices) }) - self.writeRequest(msg) - self.attach_fe_devices() - - def recv_fe_interface_connect(self, msg, req): - val = unpackMsg('netif_fe_interface_connect_t', msg) - dev = self.devices[val['handle']] - dev.evtchn = channel.eventChannel(0, self.dom) - msg = packMsg('netif_be_connect_t', - { 'domid' : self.dom, - 'netif_handle' : dev.vif, - 'evtchn' : dev.evtchn['port1'], - 'tx_shmem_frame' : val['tx_shmem_frame'], - 'rx_shmem_frame' : val['rx_shmem_frame'] }) - self.factory.writeRequest(msg) - - def send_interface_connected(self, vif): - dev = self.devices[vif] - msg = packMsg('netif_fe_interface_status_changed_t', - { 'handle' : dev.vif, - 'status' : NETIF_INTERFACE_STATUS_CONNECTED, - 'evtchn' : dev.evtchn['port2'], - 'mac' : dev.mac }) - self.writeRequest(msg) - - def send_be_create(self, vif): - dev = self.devices[vif] - msg = packMsg('netif_be_create_t', - { 'domid' : self.dom, - 'netif_handle' : dev.vif, - 'mac' : dev.mac }) - self.factory.writeRequest(msg) - - def send_be_disconnect(self, vif): - dev = self.devices[vif] - msg = packMsg('netif_be_disconnect_t', - { 'domid' : self.dom, - 'netif_handle' : dev.vif }) - self.factory.writeRequest(msg) - - def send_be_destroy(self, vif): - print 'NetifController>send_be_destroy>', 'dom=', self.dom, 'vif=', vif - PrettyPrint.prettyprint(self.sxpr()) - dev = self.devices[vif] - del self.devices[vif] - msg = packMsg('netif_be_destroy_t', - { 'domid' : self.dom, - 'netif_handle' : vif }) - self.factory.writeRequest(msg) diff --git a/tools/xen/lib/xend/server/params.py b/tools/xen/lib/xend/server/params.py deleted file mode 100644 index 7949f1431f..0000000000 --- a/tools/xen/lib/xend/server/params.py +++ /dev/null @@ -1,10 +0,0 @@ -# The following parameters could be placed in a configuration file. -PID_FILE = '/var/run/xend.pid' -LOG_FILE = '/var/log/xend.log' -USER = 'root' -CONTROL_DIR = '/var/run/xend' -MGMT_SOCK = 'xendsock' # relative to CONTROL_DIR -EVENT_PORT = 8001 - -CONSOLE_PORT_BASE = 9600 - diff --git a/tools/xen/lib/xend/sxp.py b/tools/xen/lib/xend/sxp.py deleted file mode 100644 index 01654a2377..0000000000 --- a/tools/xen/lib/xend/sxp.py +++ /dev/null @@ -1,580 +0,0 @@ -#!/usr/bin/python2 -# Copyright (C) 2004 Mike Wray -""" -Input-driven parsing for s-expression (sxp) format. -Create a parser: pin = Parser(); -Then call pin.input(buf) with your input. -Call pin.input_eof() when done. -Use pin.read() to see if a value has been parsed, pin.get_val() -to get a parsed value. You can call ready and get_val at any time - -you don't have to wait until after calling input_eof. - -""" -from __future__ import generators - -import sys -import types -import errno -import string -from StringIO import StringIO - -__all__ = [ - "mime_type", - "ParseError", - "Parser", - "atomp", - "show", - "show_xml", - "elementp", - "name", - "attributes", - "attribute", - "children", - "child", - "child_at", - "child0", - "child1", - "child2", - "child3", - "child4", - "child_value", - "has_id", - "with_id", - "child_with_id", - "elements", - "parse", - ] - -mime_type = "application/sxp" - -escapes = { - 'a': '\a', - 'b': '\b', - 't': '\t', - 'n': '\n', - 'v': '\v', - 'f': '\f', - 'r': '\r', - '\\': '\\', - '\'': '\'', - '\"': '\"'} - -k_list_open = "(" -k_list_close = ")" -k_attr_open = "@" -k_eval = "!" - -escapes_rev = {} -for k in escapes: - escapes_rev[escapes[k]] = k - -class ParseError(StandardError): - - def __init__(self, parser, value): - self.parser = parser - self.value = value - - def __str__(self): - return self.value - -class ParserState: - - def __init__(self, fn, parent=None): - self.parent = parent - self.buf = '' - self.val = [] - self.delim = None - self.fn = fn - - def push(self, fn): - return ParserState(fn, parent=self) - -class Parser: - - def __init__(self): - self.error = sys.stderr - self.reset() - - def reset(self): - self.val = [] - self.eof = 0 - self.err = 0 - self.line_no = 0 - self.char_no = 0 - self.state = None - - def push_state(self, fn): - self.state = self.state.push(fn) - - def pop_state(self): - val = self.state - self.state = self.state.parent - if self.state and self.state.fn == self.state_start: - # Return to start state - produce the value. - self.val += self.state.val - self.state.val = [] - return val - - def in_class(self, c, s): - return s.find(c) >= 0 - - def in_space_class(self, c): - return self.in_class(c, ' \t\n\v\f\r') - - def is_separator(self, c): - return self.in_class(c, '{}()<>[]!;') - - def in_comment_class(self, c): - return self.in_class(c, '#') - - def in_string_quote_class(self, c): - return self.in_class(c, '"\'') - - def in_printable_class(self, c): - return self.in_class(c, string.printable) - - def set_error_stream(self, error): - self.error = error - - def has_error(self): - return self.err > 0 - - def at_eof(self): - return self.eof - - def input_eof(self): - self.eof = 1 - self.input_char(-1) - - def input(self, buf): - if not buf or len(buf) == 0: - self.input_eof() - else: - for c in buf: - self.input_char(c) - - def input_char(self, c): - if self.at_eof(): - pass - elif c == '\n': - self.line_no += 1 - self.char_no = 0 - else: - self.char_no += 1 - - if self.state is None: - self.begin_start(None) - self.state.fn(c) - - def ready(self): - return len(self.val) > 0 - - def get_val(self): - v = self.val[0] - self.val = self.val[1:] - return v - - def get_all(self): - return self.val - - def begin_start(self, c): - self.state = ParserState(self.state_start) - - def end_start(self): - self.val += self.state.val - self.pop_state() - - def state_start(self, c): - if self.at_eof(): - self.end_start() - elif self.in_space_class(c): - pass - elif self.in_comment_class(c): - self.begin_comment(c) - elif c == k_list_open: - self.begin_list(c) - elif c == k_list_close: - raise ParseError(self, "syntax error: "+c) - elif self.in_string_quote_class(c): - self.begin_string(c) - elif self.in_printable_class(c): - self.begin_atom(c) - elif c == chr(4): - # ctrl-D, EOT: end-of-text. - self.input_eof() - else: - raise ParseError(self, "invalid character: code %d" % ord(c)) - - def begin_comment(self, c): - self.push_state(self.state_comment) - self.state.buf += c - - def end_comment(self): - self.pop_state() - - def state_comment(self, c): - if c == '\n' or self.at_eof(): - self.end_comment() - else: - self.state.buf += c - - def begin_string(self, c): - self.push_state(self.state_string) - self.state.delim = c - - def end_string(self): - val = self.state.buf - self.state.parent.val.append(val) - self.pop_state() - - def state_string(self, c): - if self.at_eof(): - raise ParseError(self, "unexpected EOF") - elif c == self.state.delim: - self.end_string() - elif c == '\\': - self.push_state(self.state_escape) - else: - self.state.buf += c - - def state_escape(self, c): - if self.at_eof(): - raise ParseError(self, "unexpected EOF") - d = escapes.get(c) - if d: - self.state.parent.buf += d - self.pop_state() - elif c == 'x': - self.state.fn = self.state_hex - self.state.val = 0 - else: - self.state.fn = self.state_octal - self.state.val = 0 - self.input_char(c) - - def state_octal(self, c): - def octaldigit(c): - self.state.val *= 8 - self.state.val += ord(c) - ord('0') - self.state.buf += c - if self.state.val < 0 or self.state.val > 0xff: - raise ParseError(self, "invalid octal escape: out of range " + self.state.buf) - if len(self.state.buf) == 3: - octaldone() - - def octaldone(): - d = chr(self.state.val) - self.state.parent.buf += d - self.pop_state() - - if self.at_eof(): - raise ParseError(self, "unexpected EOF") - elif '0' <= c <= '7': - octaldigit(c) - elif len(self.buf): - octaldone() - self.input_char(c) - - def state_hex(self, c): - def hexdone(): - d = chr(self.state.val) - self.state.parent.buf += d - self.pop_state() - - def hexdigit(c, d): - self.state.val *= 16 - self.state.val += ord(c) - ord(d) - self.state.buf += c - if self.state.val < 0 or self.state.val > 0xff: - raise ParseError(self, "invalid hex escape: out of range " + self.state.buf) - if len(self.state.buf) == 2: - hexdone() - - if self.at_eof(): - raise ParseError(self, "unexpected EOF") - elif '0' <= c <= '9': - hexdigit(c, '0') - elif 'A' <= c <= 'F': - hexdigit(c, 'A') - elif 'a' <= c <= 'f': - hexdigit(c, 'a') - elif len(buf): - hexdone() - self.input_char(c) - - def begin_atom(self, c): - self.push_state(self.state_atom) - self.state.buf = c - - def end_atom(self): - val = self.state.buf - self.state.parent.val.append(val) - self.pop_state() - - def state_atom(self, c): - if self.at_eof(): - self.end_atom() - elif (self.is_separator(c) or - self.in_space_class(c) or - self.in_comment_class(c)): - self.end_atom() - self.input_char(c) - else: - self.state.buf += c - - def begin_list(self, c): - self.push_state(self.state_list) - - def end_list(self): - val = self.state.val - self.state.parent.val.append(val) - self.pop_state() - - def state_list(self, c): - if self.at_eof(): - raise ParseError(self, "unexpected EOF") - elif c == k_list_close: - self.end_list() - else: - self.state_start(c) - -def atomp(sxpr): - if sxpr.isalnum() or sxpr == '@': - return 1 - for c in sxpr: - if c in string.whitespace: return 0 - if c in '"\'\\(){}[]<>$#&%^': return 0 - if c in string.ascii_letters: continue - if c in string.digits: continue - if c in '.-_:/~': continue - return 0 - return 1 - -def show(sxpr, out=sys.stdout): - if isinstance(sxpr, types.ListType): - out.write(k_list_open) - i = 0 - for x in sxpr: - if i: out.write(' ') - show(x, out) - i += 1 - out.write(k_list_close) - elif isinstance(sxpr, types.StringType) and atomp(sxpr): - out.write(sxpr) - else: - #out.write("'" + str(sxpr) + "'") - out.write(repr(str(sxpr))) - -def show_xml(sxpr, out=sys.stdout): - if isinstance(sxpr, types.ListType): - element = name(sxpr) - out.write('<%s' % element) - for attr in attributes(sxpr): - out.write(' %s=%s' % (attr[0], attr[1])) - out.write('>') - i = 0 - for x in children(sxpr): - if i: out.write(' ') - show_xml(x, out) - i += 1 - out.write('' % element) - elif isinstance(sxpr, types.StringType) and atomp(sxpr): - out.write(sxpr) - else: - out.write(str(sxpr)) - -def elementp(sxpr, elt=None): - return (isinstance(sxpr, types.ListType) - and len(sxpr) - and (None == elt or sxpr[0] == elt)) - -def name(sxpr): - val = None - if isinstance(sxpr, types.StringType): - val = sxpr - elif isinstance(sxpr, types.ListType) and len(sxpr): - val = sxpr[0] - return val - -def attributes(sxpr): - val = [] - if isinstance(sxpr, types.ListType) and len(sxpr) > 1: - attr = sxpr[1] - if elementp(attr, k_attr_open): - val = attr[1:] - return val - -def attribute(sxpr, key, val=None): - for x in attributes(sxpr): - if x[0] == key: - val = x[1] - break - return val - -def children(sxpr, elt=None): - val = [] - if isinstance(sxpr, types.ListType) and len(sxpr) > 1: - i = 1 - x = sxpr[i] - if elementp(x, k_attr_open): - i += 1 - val = sxpr[i : ] - if elt: - def iselt(x): - return elementp(x, elt) - val = filter(iselt, val) - return val - -def child(sxpr, elt, val=None): - for x in children(sxpr): - if elementp(x, elt): - val = x - break - return val - -def child_at(sxpr, index, val=None): - kids = children(sxpr) - if len(kids) > index: - val = kids[index] - return val - -def child0(sxpr, val=None): - return child_at(sxpr, 0, val) - -def child1(sxpr, val=None): - return child_at(sxpr, 1, val) - -def child2(sxpr, val=None): - return child_at(sxpr, 2, val) - -def child3(sxpr, val=None): - return child_at(sxpr, 3, val) - -def child4(sxpr, val=None): - return child_at(sxpr, 4, val) - -def child_value(sxpr, elt, val=None): - kid = child(sxpr, elt) - if kid: - val = child_at(kid, 0, val) - return val - -def has_id(sxpr, id): - """Test if an s-expression has a given id. - """ - return attribute(sxpr, 'id') == id - -def with_id(sxpr, id, val=None): - """Find the first s-expression with a given id, at any depth. - - sxpr s-exp or list - id id - val value if not found (default None) - - return s-exp or val - """ - if isinstance(sxpr, types.ListType): - for n in sxpr: - if has_id(n, id): - val = n - break - v = with_id(n, id) - if v is None: continue - val = v - break - return val - -def child_with_id(sxpr, id, val=None): - """Find the first child with a given id. - - sxpr s-exp or list - id id - val value if not found (default None) - - return s-exp or val - """ - if isinstance(sxpr, types.ListType): - for n in sxpr: - if has_id(n, id): - val = n - break - return val - -def elements(sxpr, ctxt=None): - """Generate elements (at any depth). - Visit elements in pre-order. - Values generated are (node, context) - The context is None if there is no parent, otherwise - (index, parent, context) where index is the node's index w.r.t its parent, - and context is the parent's context. - - sxpr s-exp - - returns generator - """ - yield (sxpr, ctxt) - i = 0 - for n in children(sxpr): - if isinstance(n, types.ListType): - # Calling elements() recursively does not generate recursively, - # it just returns a generator object. So we must iterate over it. - for v in elements(n, (i, sxpr, ctxt)): - yield v - i += 1 - -def to_string(sxpr): - """Convert an sxpr to a string. - - sxpr sxpr - returns string - """ - io = StringIO() - show(sxpr, io) - io.seek(0) - val = io.getvalue() - io.close() - return val - -def from_string(str): - """Create an sxpr by parsing a string. - - str string - returns sxpr - """ - io = StringIO(str) - return parse(io) - -def parse(io): - """Completely parse all input from 'io'. - - io input file object - returns list of values, None if incomplete - raises ParseError on parse error - """ - pin = Parser() - while 1: - buf = io.readline() - pin.input(buf) - if len(buf) == 0: - break - if pin.ready(): - val = pin.get_all() - else: - val = None - return val - - -if __name__ == '__main__': - print ">main" - pin = Parser() - while 1: - buf = sys.stdin.read(1024) - #buf = sys.stdin.readline() - pin.input(buf) - while pin.ready(): - val = pin.get_val() - print - print '****** val=', val - if len(buf) == 0: - break - diff --git a/tools/xen/lib/xm/__init__.py b/tools/xen/lib/xm/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tools/xen/lib/xm/create.py b/tools/xen/lib/xm/create.py deleted file mode 100644 index 12e2e8010c..0000000000 --- a/tools/xen/lib/xm/create.py +++ /dev/null @@ -1,366 +0,0 @@ -# Copyright (C) 2004 Mike Wray -"""Domain creation. -""" -import string -import sys - -from xen.xend import sxp -from xen.xend import PrettyPrint -from xen.xend.XendClient import server - -from xen.xm.opts import * - -gopts = Opts(use="""[options] - -Create a domain. -""") - -gopts.opt('help', short='h', - fn=set_true, default=0, - use="Print this help.") - -gopts.opt('quiet', short='q', - fn=set_true, default=0, - use="Quiet.") - -gopts.opt('path', val='PATH', - fn=set_value, default='.:/etc/xen', - use="Search path for default scripts.") - -gopts.opt('defaults', short='f', val='FILE', - fn=set_value, default='xmdefaults', - use="Use the given default script.") - -gopts.opt('config', short='F', val='FILE', - fn=set_value, default=None, - use='Domain configuration to use (SXP).') - -gopts.opt('load', short='L', val='FILE', - fn=set_value, default=None, - use='Domain saved state to load.') - -gopts.opt('define', short='D', val='VAR=VAL', - fn=set_var, default=None, - use="""Set a variable before loading defaults, e.g. '-D vmid=3' - to set vmid. May be repeated to set more thanone variable.""") - -gopts.opt('dryrun', short='n', - fn=set_true, default=0, - use="Dry run - print the config but don't create the domain.") - -gopts.opt('name', short='N', val='NAME', - fn=set_value, default=None, - use="Domain name.") - -gopts.opt('console', short='c', - fn=set_true, default=0, - use="Connect to console after domain is created.") - -gopts.opt('kernel', short='k', val='FILE', - fn=set_value, default=None, - use="Path to kernel image.") - -gopts.opt('ramdisk', short='r', val='FILE', - fn=set_value, default='', - use="Path to ramdisk.") - -gopts.opt('builder', short='b', val='FUNCTION', - fn=set_value, default='linux', - use="Function to use to build the domain.") - -gopts.opt('memory', short='m', val='MEMORY', - fn=set_value, default=128, - use="Domain memory in MB.") - -gopts.opt('blkif', - fn=set_true, default=0, - use="Make the domain a block device backend.") - -gopts.opt('netif', - fn=set_true, default=0, - use="Make the domain a network interface backend.") - -gopts.opt('disk', short='d', val='phy:DEV,VDEV,MODE', - fn=append_value, default=[], - use="""Add a disk device to a domain. The physical device is DEV, which - is exported to the domain as VDEV. The disk is read-only if MODE - is 'r', read-write if MODE is 'w'. - The option may be repeated to add more than one disk. - """) - -gopts.opt('pci', val='BUS,DEV,FUNC', - fn=append_value, default=[], - use="""Add a PCI device to a domain, using given params (in hex). - For example '-pci c0,02,1a'. - The option may be repeated to add more than one pci device. - """) - -gopts.opt('ipaddr', short='i', val="IPADDR", - fn=append_value, default=[], - use="Add an IP address to the domain.") - -gopts.opt('vif', val="mac=MAC,bridge=BRIDGE", - fn=append_value, default=[], - use="""Add a network interface with the given MAC address and bridge. - If mac is not specified a random MAC address is used. - If bridge is not specified the default bridge is used. - This option may be repeated to add more than one vif. - Specifying vifs will increase the number of interfaces as needed. - """) - -gopts.opt('nics', val="NUM", - fn=set_int, default=1, - use="""Set the number of network interfaces. - Use the vif option to define interface parameters, otherwise - defaults are used. Specifying vifs will increase the - number of interfaces as needed. - """) - -gopts.opt('root', short='R', val='DEVICE', - fn=set_value, default='', - use="""Set the root= parameter on the kernel command line. - Use a device, e.g. /dev/sda1, or /dev/nfs for NFS root.""") - -gopts.opt('extra', short='E', val="ARGS", - fn=set_value, default='', - use="Set extra arguments to append to the kernel command line.") - -gopts.opt('ip', short='I', val='IPADDR', - fn=set_value, default='', - use="Set the kernel IP interface address.") - -gopts.opt('gateway', val="IPADDR", - fn=set_value, default='', - use="Set the kernel IP gateway.") - -gopts.opt('netmask', val="MASK", - fn=set_value, default = '', - use="Set the kernel IP netmask.") - -gopts.opt('hostname', val="NAME", - fn=set_value, default='', - use="Set the kernel IP hostname.") - -gopts.opt('interface', val="INTF", - fn=set_value, default="eth0", - use="Set the kernel IP interface name.") - -gopts.opt('dhcp', val="off|dhcp", - fn=set_value, default='off', - use="Set the kernel dhcp option.") - -gopts.opt('nfs_server', val="IPADDR", - fn=set_value, default=None, - use="Set the address of the NFS server for NFS root.") - -gopts.opt('nfs_root', val="PATH", - fn=set_value, default=None, - use="Set the path of the root NFS directory.") - -def strip(pre, s): - """Strip prefix 'pre' if present. - """ - if s.startswith(pre): - return s[len(pre):] - else: - return s - -def configure_image(config, opts): - """Create the image config. - """ - config_image = [ opts.builder ] - config_image.append([ 'kernel', os.path.abspath(opts.kernel) ]) - if opts.ramdisk: - config_image.append([ 'ramdisk', os.path.abspath(opts.ramdisk) ]) - if opts.cmdline_ip: - cmdline_ip = strip('ip=', opts.cmdline_ip) - config_image.append(['ip', cmdline_ip]) - if opts.root: - cmdline_root = strip('root=', opts.root) - config_image.append(['root', cmdline_root]) - if opts.extra: - config_image.append(['args', opts.extra]) - config.append(['image', config_image ]) - -def configure_disks(config_devs, opts): - """Create the config for disks (virtual block devices). - """ - for (uname, dev, mode) in opts.disk: - config_vbd = ['vbd', - ['uname', uname], - ['dev', dev ], - ['mode', mode ] ] - config_devs.append(['device', config_vbd]) - -def configure_pci(config_devs, opts): - """Create the config for pci devices. - """ - for (bus, dev, func) in opts.pci: - config_pci = ['pci', ['bus', bus], ['dev', dev], ['func', func]] - config_devs.append(['device', config_pci]) - -def configure_vifs(config_devs, opts): - """Create the config for virtual network interfaces. - """ - vifs = opts.vif - vifs_n = max(opts.nics, len(vifs)) - - for idx in range(0, vifs_n): - if idx < len(vifs): - d = vifs[idx] - mac = d.get('mac') - bridge = d.get('bridge') - else: - mac = None - bridge = None - config_vif = ['vif'] - if mac: - config_vif.append(['mac', mac]) - if bridge: - config_vif.append(['bridge', bridge]) - config_devs.append(['device', config_vif]) - -def configure_vfr(config, opts): - if not opts.ipaddr: return - config_vfr = ['vfr'] - idx = 0 # No way of saying which IP is for which vif? - for ip in opts.ipaddr: - config_vfr.append(['vif', ['id', idx], ['ip', ip]]) - config.append(config_vfr) - - -def make_config(opts): - """Create the domain configuration. - """ - - config = ['vm', - ['name', opts.name ], - ['memory', opts.memory ] ] - if opts.cpu: - config.append(['cpu', opts.cpu]) - if opts.blkif: - config.append(['backend', ['blkif']]) - if opts.netif: - config.append(['backend', ['netif']]) - - configure_image(config, opts) - config_devs = [] - configure_disks(config_devs, opts) - configure_pci(config_devs, opts) - configure_vifs(config_devs, opts) - config += config_devs - return config - -def preprocess_disk(opts): - if not opts.disk: return - disk = [] - for v in opts.disk: - d = v.split(',') - if len(d) != 3: - opts.err('Invalid disk specifier: ' + v) - disk.append(d) - opts.disk = disk - -def preprocess_pci(opts): - if not opts.pci: return - pci = [] - for v in opts.pci: - d = v.split(',') - if len(d) != 3: - opts.err('Invalid pci specifier: ' + v) - # Components are in hex: add hex specifier. - hexd = map(lambda v: '0x'+v, d) - pci.append(hexd) - opts.pci = pci - -def preprocess_vifs(opts): - if not opts.vif: return - vifs = [] - for vif in opts.vif: - d = {} - a = vif.split(',') - for b in a: - (k, v) = b.strip().split('=') - k = k.strip() - v = v.strip() - if k not in ['mac', 'bridge']: - opts.err('Invalid vif specifier: ' + vif) - d[k] = v - vifs.append(d) - opts.vif = vifs - -def preprocess_ip(opts): - setip = (opts.hostname or opts.netmask - or opts.gateway or opts.dhcp or opts.interface) - if not setip: return - #if not opts - ip = (opts.ip - + ':' - + ':' + opts.gateway - + ':' + opts.netmask - + ':' + opts.hostname - + ':' + opts.interface - + ':' + opts.dhcp) - opts.cmdline_ip = ip - -def preprocess_nfs(opts): - if (opts.nfs_root or opts.nfs_server): - if (not opts.nfs_root) or (not opts.nfs_server): - opts.err('Must set nfs root and nfs server') - else: - return - nfs = 'nfsroot=' + opts.nfs_server + ':' + opts.nfs_root - opts.extra = nfs + ' ' + opts.extra - -def preprocess(opts): - if not opts.kernel: - opts.err("No kernel specified") - preprocess_disk(opts) - preprocess_pci(opts) - preprocess_vifs(opts) - preprocess_ip(opts) - preprocess_nfs(opts) - -def make_domain(opts, config): - """Create, build and start a domain. - Returns: [int] the ID of the new domain. - """ - if opts.vals.load: - filename = os.path.abspath(opts.vals.load) - dominfo = server.xend_domain_restore(filename, config) - else: - dominfo = server.xend_domain_create(config) - - dom = int(sxp.child_value(dominfo, 'id')) - console_info = sxp.child(dominfo, 'console') - if console_info: - console_port = int(sxp.child_value(console_info, 'port')) - else: - console_port = None - - if server.xend_domain_unpause(dom) < 0: - server.xend_domain_destroy(dom) - opts.err("Failed to start domain %d" % dom) - opts.info("Started domain %d, console on port %d" - % (dom, console_port)) - return (dom, console_port) - -def main(argv): - opts = gopts - args = opts.parse(argv) - if opts.vals.help: - opts.usage() - return - if opts.vals.config: - pass - else: - opts.load_defaults() - preprocess(opts.vals) - config = make_config(opts.vals) - if opts.vals.dryrun: - PrettyPrint.prettyprint(config) - else: - make_domain(opts, config) - -if __name__ == '__main__': - main(sys.argv) diff --git a/tools/xen/lib/xm/main.py b/tools/xen/lib/xm/main.py deleted file mode 100644 index 3ab5d23cf7..0000000000 --- a/tools/xen/lib/xm/main.py +++ /dev/null @@ -1,448 +0,0 @@ -# Copyright (C) 2004 Mike Wray -"""Grand unified management application for Xen. -""" -import os -import os.path -import sys -from getopt import getopt - -from xen.xend import PrettyPrint -from xen.xend import sxp -from xen.xend.XendClient import server -from xen.xm import create, shutdown - -class Prog: - """Base class for sub-programs. - """ - - """Program group it belongs to""" - group = 'all' - """Program name.""" - name = '??' - """Short program info.""" - info = '' - - def __init__(self, xm): - self.xm = xm - - def err(self, msg): - self.xm.err(msg) - - def help(self, args): - self.shortHelp(args) - - def shortHelp(self, args): - print "%-14s %s" % (self.name, self.info) - - def main(self, args): - """Program main entry point. - """ - pass - - -class ProgUnknown(Prog): - - name = 'unknown' - info = '' - - def help(self, args): - self.xm.err("Unknown command: %s\nTry '%s help' for more information." - % (args[0], self.xm.name)) - - main = help - -class Xm: - """Main application. - """ - - def __init__(self): - self.name = 'xm' - self.unknown = ProgUnknown(self) - self.progs = {} - - def err(self, msg): - print >>sys.stderr, "Error:", msg - sys.exit(1) - - def main(self, args): - """Main entry point. Dispatches to the progs. - """ - self.name = args[0] - if len(args) < 2: - self.err("Missing command\nTry '%s help' for more information." - % self.name) - help = self.helparg(args) - p = self.getprog(args[1], self.unknown) - if help: - p.help(args[1:]) - else: - p.main(args[1:]) - - def helparg(self, args): - for a in args: - if a in ['-h', '--help']: - return 1 - return 0 - - def prog(self, pklass): - """Add a sub-program. - - pklass program class (Prog subclass) - """ - p = pklass(self) - self.progs[p.name] = p - return p - - def getprog(self, name, val=None): - """Get a sub-program. - """ - return self.progs.get(name, val) - - def proglist(self): - """Get a list of sub-programs, ordered by group. - """ - groups = {} - for p in self.progs.values(): - l = groups.get(p.group, []) - l.append(p) - groups[p.group] = l - kl = groups.keys() - kl.sort() - pl = [] - for k in kl: - l = groups[k] - l.sort() - pl += l - return pl - -# Create the application object, then add the sub-program classes. -xm = Xm() - -class ProgHelp(Prog): - - name = "help" - info = "Print help." - - def help(self, args): - if len(args) == 2: - name = args[1] - p = self.xm.getprog(name) - if p: - p.help(args[1:]) - else: - print '%s: Unknown command: %s' % (self.name, name) - else: - for p in self.xm.proglist(): - p.shortHelp(args) - print "\nTry '%s help CMD' for help on CMD" % self.xm.name - - main = help - -xm.prog(ProgHelp) - -class ProgCreate(Prog): - - group = 'domain' - name = "create" - info = """Create a domain.""" - - def help(self, args): - create.main([args[0], '-h']) - - def main(self, args): - create.main(args) - -xm.prog(ProgCreate) - -class ProgSave(Prog): - group = 'domain' - name = "save" - info = """Save domain state (and config) to file.""" - - def help(self, args): - print args[0], "DOM FILE" - print """\nSave domain with id DOM to FILE.""" - - def main(self, args): - if len(args) < 3: self.err("%s: Missing arguments" % args[0]) - dom = args[1] - savefile = os.path.abspath(args[2]) - server.xend_domain_save(dom, savefile) - -xm.prog(ProgSave) - -class ProgRestore(Prog): - group = 'domain' - name = "restore" - info = """Create a domain from a saved state.""" - - def help(self, args): - print args[0], "FILE [CONFIG]" - print "\nRestore a domain from FILE using configuration CONFIG." - - def main(self, help, args): - if len(args) < 2: self.err("%s: Missing arguments" % args[0]) - savefile = os.path.abspath(args[1]) - if len(args) >= 3: - configfile = os.path.abspath(args[2]) - else: - configfile = None - info = server.xend_domain_restore(savefile, configfile) - PrettyPrint.prettyprint(info) - -xm.prog(ProgRestore) - -class ProgList(Prog): - group = 'domain' - name = "list" - info = """List info about domains.""" - - short_options = 'l' - long_options = ['long'] - - def help(self, args): - if help: - print args[0], '[options] [DOM...]' - print """\nGet information about domains. - Either all domains or the domains given. - - -l, --long Get more detailed information. - """ - return - - def main(self, args): - use_long = 0 - (options, params) = getopt(args[1:], - self.short_options, - self.long_options) - n = len(params) - for (k, v) in options: - if k in ['-l', '--long']: - use_long = 1 - - if n == 0: - doms = map(int, server.xend_domains()) - doms.sort() - else: - doms = map(int, params) - - if use_long: - self.long_list(doms) - else: - self.brief_list(doms) - - def brief_list(self, doms): - print 'Dom Name Mem(MB) CPU State Time(s)' - for dom in doms: - info = server.xend_domain(dom) - d = {} - d['dom'] = int(dom) - d['name'] = sxp.child_value(info, 'name', '??') - d['mem'] = int(sxp.child_value(info, 'memory', '0')) - d['cpu'] = int(sxp.child_value(info, 'cpu', '0')) - d['state'] = sxp.child_value(info, 'state', '??') - d['cpu_time'] = float(sxp.child_value(info, 'cpu_time', '0')) - print ("%(dom)-4d %(name)-16s %(mem)7d %(cpu)3d %(state)5s %(cpu_time)7.1f" % d) - - def long_list(self, doms): - for dom in doms: - info = server.xend_domain(dom) - print '\nDomain %d' % dom - PrettyPrint.prettyprint(info) - -xm.prog(ProgList) - -class ProgDestroy(Prog): - group = 'domain' - name = "destroy" - info = """Terminate a domain immediately.""" - - def help(self, args): - print args[0], 'DOM' - print '\nTerminate domain DOM immediately.' - - def main(self, args): - if len(args) < 2: self.err("%s: Missing domain" % args[0]) - dom = args[1] - server.xend_domain_destroy(dom) - -xm.prog(ProgDestroy) - -class ProgShutdown(Prog): - group = 'domain' - name = "shutdown" - info = """Shutdown a domain.""" - - def help(self, args): - shutdown.main([args[0], '-h']) - - def main(self, args): - shutdown.main(args) - -xm.prog(ProgShutdown) - -class ProgPause(Prog): - group = 'domain' - name = "pause" - info = """Pause execution of a domain.""" - - def help(self, args): - print args[0], 'DOM' - print '\nPause execution of domain DOM.' - - def main(self, args): - if len(args) < 2: self.err("%s: Missing domain" % args[0]) - dom = args[1] - server.xend_domain_pause(dom) - -xm.prog(ProgPause) - -class ProgUnpause(Prog): - group = 'domain' - name = "unpause" - info = """Unpause a paused domain.""" - - def help(self, args): - print args[0], 'DOM' - print '\nUnpause execution of domain DOM.' - - def main(self, args): - if len(args) < 2: self.err("%s: Missing domain" % args[0]) - dom = args[1] - server.xend_domain_unpause(dom) - -xm.prog(ProgUnpause) - -class ProgPincpu(Prog): - group = 'domain' - name = "pincpu" - info = """Pin a domain to a cpu. """ - - def help(self, args): - print args[0],'DOM CPU' - print '\nPin domain DOM to cpu CPU.' - - def main(self, args): - if len(args) != 3: self.err("%s: Invalid argument(s)" % args[0]) - v = map(int, args[1:3]) - server.xend_domain_pincpu(*v) - -xm.prog(ProgPincpu) - -class ProgBvt(Prog): - group = 'scheduler' - name = "bvt" - info = """Set BVT scheduler parameters.""" - - def help(self, args): - print args[0], "DOM MCUADV WARP WARPL WARPU" - print '\nSet Borrowed Virtual Time scheduler parameters.' - - def main(self, args): - if len(args) != 6: self.err("%s: Invalid argument(s)" % args[0]) - v = map(int, args[1:6]) - server.xend_domain_cpu_bvt_set(*v) - -xm.prog(ProgBvt) - -class ProgBvtslice(Prog): - group = 'scheduler' - name = "bvtslice" - info = """Set the BVT scheduler slice.""" - - def help(self, args): - print args[0], 'SLICE' - print '\nSet Borrowed Virtual Time scheduler slice.' - - def main(self, args): - if len(args) < 2: self.err('%s: Missing slice' % args[0]) - server.xend_node_cpu_bvt_slice_set(slice) - -xm.prog(ProgBvtslice) - -class ProgAtropos(Prog): - group = 'scheduler' - name= "atropos" - info = """Set atropos parameters.""" - - def help(self, args): - print args[0], "DOM PERIOD SLICE LATENCY XTRATIME" - print "\nSet atropos parameters." - - def main(self, args): - if len(args) != 5: self.err("%s: Invalid argument(s)" % args[0]) - v = map(int, args[1:5]) - server.xend_domain_cpu_atropos_set(*v) - -xm.prog(ProgAtropos) - -class ProgRrobin(Prog): - group = 'scheduler' - name = "rrobin" - info = """Set round robin slice.""" - - def help(self, args): - print args[0], "SLICE" - print "\nSet round robin scheduler slice." - - def main(self, args): - if len(args) != 2: self.err("%s: Invalid argument(s)" % args[0]) - rrslice = int(args[1]) - server.xend_node_rrobin_set(rrslice) - -xm.prog(ProgRrobin) - -class ProgInfo(Prog): - group = 'host' - name = "info" - info = """Get information about the xen host.""" - - def main(self, args): - info = server.xend_node() - for x in info[1:]: - print "%-23s:" % x[0], x[1] - -xm.prog(ProgInfo) - -class ProgConsoles(Prog): - group = 'console' - name = "consoles" - info = """Get information about domain consoles.""" - - def main(self, args): - l = server.xend_consoles() - print "Dom Port Id" - for x in l: - info = server.xend_console(x) - d = {} - d['dom'] = sxp.child(info, 'dst', ['dst', '?', '?'])[1] - d['port'] = sxp.child_value(info, 'port', '?') - d['id'] = sxp.child_value(info, 'id', '?') - print "%(dom)3s %(port)4s %(id)3s" % d - -xm.prog(ProgConsoles) - -class ProgConsole(Prog): - group = 'console' - name = "console" - info = """Open a console to a domain.""" - - def help(self, args): - print "console DOM" - print "\nOpen a console to domain DOM." - - def main(self, args): - if len(args) < 2: self.err("%s: Missing domain" % args[0]) - dom = args[1] - info = server.xend_domain(dom) - console = sxp.child(info, "console") - if not console: - self.err("No console information") - port = sxp.child_value(console, "port") - from xen.util import console_client - console_client.connect("localhost", int(port)) - -xm.prog(ProgConsole) - -def main(args): - xm.main(args) diff --git a/tools/xen/lib/xm/opts.py b/tools/xen/lib/xm/opts.py deleted file mode 100644 index eb07936f1e..0000000000 --- a/tools/xen/lib/xm/opts.py +++ /dev/null @@ -1,340 +0,0 @@ -# Copyright (C) 2004 Mike Wray -"""Object-oriented command-line option support. -""" -from getopt import getopt -import os -import os.path -import sys -import types - -class Opt: - """An individual option. - """ - def __init__(self, opts, name, short=None, long=None, - val=None, fn=None, use=None, default=None): - """Create an option. - - opts parent options object - name name of the field it controls - short short (1-char) command line switch (optional) - long long command-line switch. Defaults to option name. - val string used to print option args in help. - If val is not specified the option has no arg. - fn function to call when the option is specified. - use usage (help) string - default default value if not specified on command-line - """ - self.opts = opts - self.name = name - self.short = short - if long is None: - long = name - self.long = long - self.val = val - self.use = use - self.default = default - self.optkeys = [] - if self.short: - self.optkeys.append('-' + self.short) - if self.long: - self.optkeys.append('--' + self.long) - self.fn = fn - self.specified_opt = None - self.specified_val = None - self.value = None - self.set(default) - - def __repr__(self): - return self.name + '=' + str(self.specified_val) - - __str__ = __repr__ - - def set(self, value): - """Set the option value. - """ - self.opts.setopt(self.name, value) - - def get(self): - """Get the option value. - """ - return self.opts.getopt(self.name) - - def append(self, value): - """Append a value to the option value. - """ - v = self.get() or [] - v.append(value) - self.set(v) - - def short_opt(self): - """Short option spec. - """ - if self.short: - if self.val: - return self.short + ':' - else: - return self.short - else: - return None - - def long_opt(self): - """Long option spec. - """ - if self.long: - if self.val: - return self.long + '=' - else: - return self.long - else: - return None - - def show(self): - sep = '' - for x in self.optkeys: - print sep, x, - sep = ',' - if self.val: - print self.val, - print - if self.use: - print '\t', - print self.use - if self.val: - print '\tDefault', self.default or 'None' - - def specify(self, k, v): - """Specify the option. Called when the option is set - from the command line. - - k option switch used - v optional value given (if any) - """ - if k in self.optkeys: - if self.val is None and v: - self.opts.err("Option '%s' does not take a value" % k) - self.specified_opt = k - self.specified_val = v - if self.fn: - self.fn(self, k, v) - return 1 - else: - return 0 - - def specified(self): - """Test whether the option has been specified: set - from the command line. - """ - return self.specified_opt - -class OptVals: - """Class to hold option values. - """ - pass - -class Opts: - """Container for options. - """ - def __init__(self, use=None): - """Options constructor. - - use usage string - """ - self.use = use - # List of options. - self.options = [] - # Options indexed by name. - self.options_map = {} - # Command-line arguments. - self.argv = [] - # Option values. - self.vals = OptVals() - self.vals.quiet = 0 - # Variables for default scripts. - self.vars = {} - - def __repr__(self): - return '\n'.join(map(str, self.options)) - - __str__ = __repr__ - - def opt(self, name, **args): - """Add an option. - - name option name - **args keyword params for option constructor - """ - x = Opt(self, name, **args) - self.options.append(x) - self.options_map[name] = x - return x - - def setvar(self, var, val): - """Set a default script variable. - """ - self.vars[var] = val - - def getvar(self, var): - """Get a default script variable. - """ - return self.vars.get(var) - - def option(self, name): - """Get an option (object). - """ - return self.options_map.get(name) - - def setopt(self, name, val): - """Set an option value. - An option can also be set using 'opts.vals.name = val'. - """ - setattr(self.vals, name, val) - - def getopt(self, name): - """Get an option value. - An option value can also be got using 'opts.vals.name'. - """ - getattr(self.vals, name) - - def specified(self, name): - """Test if an option has been specified. - """ - opt = self.option(name) - return opt and opt.specified() - - def err(self, msg): - """Print an error to stderr and exit. - """ - print >>sys.stderr, "Error:", msg - sys.exit(1) - - def info(self, msg): - """Print a message to stdout (unless quiet is set). - """ - if self.vals.quiet: return - print msg - - def warn(self, msg): - """Print a warning to stdout. - """ - print >>sys.stderr, "Warning:", msg - - def parse(self, argv): - """Parse arguments argv using the options. - - return remaining arguments - """ - self.argv = argv - (vals, args) = getopt(argv[1:], self.short_opts(), self.long_opts()) - self.args = args - for (k, v) in vals: - for opt in self.options: - if opt.specify(k, v): break - else: - print >>sys.stderr, "Error: Unknown option:", k - self.usage() - return args - - def short_opts(self): - """Get short options specifier for getopt. - """ - l = [] - for x in self.options: - y = x.short_opt() - if not y: continue - l.append(y) - return ''.join(l) - - def long_opts(self): - """Get long options specifier for getopt. - """ - l = [] - for x in self.options: - y = x.long_opt() - if not y: continue - l.append(y) - return l - - def usage(self): - print 'Usage: ', self.argv[0], self.use or 'OPTIONS' - for opt in self.options: - opt.show() - - def load_defaults(self): - """Load a defaults script. Assumes these options set: - 'path' search path - 'default' script name - """ - for x in [ '' ] + self.vals.path.split(':'): - if x: - p = os.path.join(x, self.vals.defaults) - else: - p = self.vals.defaults - if os.path.exists(p): - self.load(p) - break - else: - self.err("Cannot open defaults file %s" % self.vals.defaults) - - def load(self, defaults, help=0): - """Load a defaults file. Local variables in the file - are used to set options with the same names. - Variables are not used to set options that are already specified. - """ - # Create global and lobal dicts for the file. - # Initialize locals to the vars. - # Use exec to do the standard imports and - # define variables we are passing to the script. - globals = {} - locals = {} - locals.update(self.vars) - cmd = '\n'.join(["import sys", - "import os", - "import os.path", - "import xen.util.ip", - "xm_file = '%s'" % defaults, - "xm_help = %d" % help ]) - exec cmd in globals, locals - execfile(defaults, globals, locals) - if help: return - # Extract the values set by the script and set the corresponding - # options, if not set on the command line. - vtypes = [ types.StringType, - types.ListType, - types.IntType, - types.FloatType - ] - for (k, v) in locals.items(): - if self.specified(k): continue - if not(type(v) in vtypes): continue - self.setopt(k, v) - -def set_true(opt, k, v): - """Set an option true.""" - opt.set(1) - -def set_false(opt, k, v): - """Set an option false.""" - opt.set(0) - -def set_value(opt, k, v): - """Set an option to a valoue.""" - opt.set(v) - -def set_int(opt, k, v): - """Set an option to an integer value.""" - try: - v = int(v) - except: - opt.opts.err('Invalid value: ' + str(v)) - opt.set(v) - -def append_value(opt, k, v): - """Append a value to a list option.""" - opt.append(v) - -def set_var(opt, k, v): - """Set a default script variable. - """ - (var, val) = v.strip().split('=') - opt.opts.setvar(var.strip(), val.strip()) - diff --git a/tools/xen/lib/xm/shutdown.py b/tools/xen/lib/xm/shutdown.py deleted file mode 100644 index aaa354554a..0000000000 --- a/tools/xen/lib/xm/shutdown.py +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright (C) 2004 Mike Wray -"""Domain shutdown. -""" -import string -import sys -import time - -from xen.xend.XendClient import server -from xen.xm.opts import * - -gopts = Opts(use="""[options] [DOM] - -Shutdown one or more domains gracefully.""") - -gopts.opt('help', short='h', - fn=set_true, default=0, - use="Print this help.") - -gopts.opt('all', short='a', - fn=set_true, default=0, - use="Shutdown all domains.") - -gopts.opt('wait', short='w', - fn=set_true, default=0, - use='Wait for shutdown to complete.') - -gopts.opt('norestart', short='n', - fn=set_true, default=0, - use='Prevent domain restart.') - -def shutdown(opts, doms, wait): - def domains(): - return [ int(a) for a in server.xend_domains() ] - if doms == None: doms = domains() - if 0 in doms: - doms.remove(0) - for d in doms: - server.xend_domain_shutdown(d) - if wait: - while doms: - alive = domains() - dead = [] - for d in doms: - if d in alive: continue - dead.append(d) - for d in dead: - opts.info("Domain %d terminated" % d) - doms.remove(d) - time.sleep(1) - opts.info("All domains terminated") - -def main_all(opts, args): - shutdown(opts, None, opts.vals.wait) - -def main_dom(opts, args): - if len(args) < 1: opts.err('Missing domain') - dom = args[0] - try: - domid = int(dom) - except: - opts.err('Invalid domain: ' + dom) - shutdown(opts, [ domid ], opts.vals.wait) - -def main(argv): - opts = gopts - args = opts.parse(argv) - if opts.vals.help: - opts.usage() - return - print 'shutdown.main>', len(args), args - if opts.vals.all: - main_all(opts, args) - else: - main_dom(opts, args) - diff --git a/tools/xen/setup.py b/tools/xen/setup.py deleted file mode 100644 index 1f0e959d08..0000000000 --- a/tools/xen/setup.py +++ /dev/null @@ -1,17 +0,0 @@ - -from distutils.core import setup, Extension - -setup(name = 'xen', - version = '1.0', - description = 'Xen', - author = 'Mike Wray', - author_email = 'mike.wray@hp.com', - packages = ['xen', - 'xen.ext', - 'xen.util', - 'xen.xend', - 'xen.xend.server', - 'xen.xm', - ], - package_dir = { 'xen': 'lib' }, - ) diff --git a/tools/xen/vifctl b/tools/xen/vifctl deleted file mode 100644 index efd0b0b063..0000000000 --- a/tools/xen/vifctl +++ /dev/null @@ -1,149 +0,0 @@ -#!/usr/bin/python -# -*- mode: python; -*- -#============================================================================ -# Xen vif control script. -# -# vifctl init [bridge=] [interface=] -# -# Called when xend starts up. Default behaviour is to create -# and add to it, moving its IP address to and adjusting routes. -# -# vifctl (up|down) vif= mac= [bridge=] (ipaddr=)* -# -# Called when a vif is brought up or down. Default behaviour is to add -# the vif to on up and remove it from the bridge on down. -# If ipaddr is specified, iptables rules for the ip addresses are -# added on up and removed on down. The bridge a vif is added to can -# be set in the vm config. -# -# The default bridge is nbe-br. -# The default interface is eth0. -# -#============================================================================ - -import sys -import types - -from xen.util import Brctl - -from xen.xend import XendRoot -xroot = XendRoot.instance() - -class VifControl: - - prefix = 'vifctl_' - - DEFAULT_BRIDGE = 'nbe-br' - DEFAULT_INTERFACE = 'eth0' - - def __init__(self): - self.name = 'vifctl' - - def main(self, args): - #print self.name, args - if len(args) < 2: - usage(args) - self.name = args[0] - cmd = self.prefix + args[1] - meth = getattr(self, cmd, self.unknown) - meth(args[1:]) - - def usage(self, args, out=sys.stderr): - print >>out, 'Missing command, try \n%s help' % self.name - - def unknown(self, args, out=sys.stderr): - print >>out, 'Unknown command:', args[1] - self.help(out=out) - sys.exit(1) - - def help(self, out=sys.stdout): - print >>out, 'Commands are:', - for x in vars(self): - if x.startswith(prefix): - cmd = x[len(prefix):] - print >>out, cmd, - print >>out - - def getparams(self, d, args, req=[]): - """Parse args of the form 'key=val'. Valid keys are the ones - in the dict 'd' passed in. If entries in 'd' have list values the - values of the keys are appended. - - If 'req' is specified it is a list of required keys. - """ - for x in args: - (k, v) = x.split('=') - k = k.strip() - v = v.strip() - if k not in d: - print >>sys.stderr, 'Invalid parameter: ', k - sys.exit(1) - vold = d[k] - if isinstance(vold , types.ListType): - d[k] = vold + v - else: - d[k] = v - for x in req: - if not d[x]: - print >>sys.stderr, 'Missing parameter:', x - sys.exit(1) - return d - - def vifctl_help(self, args): - self.help() - - def default_bridge(self): - return xroot.get_config_value('bridge', self.DEFAULT_BRIDGE) - - def default_interface(self): - return xroot.get_config_value('interface', self.DEFAULT_INTERFACE) - - def vifctl_init(self, args): - """Entry point for 'vifctl init'. - """ - d = { 'bridge' : self.default_bridge(), - 'interface': self.default_interface() } - params = self.getparams(d, args[1:]) - interface = params['interface'] - bridge = params['bridge'] - # Create bridge 'bridge'. - Brctl.bridge_create(bridge) - # Reconfigure so that 'interface' is added to 'bridge', - # and 'bridge' has the IP address from 'interface'. - Brctl.reconfigure(interface, bridge) - - def vifparams(self, args): - d = { 'vif' : None, - 'mac' : None, - 'bridge': self.default_bridge(), - 'ipaddr': [] } - d = self.getparams(d, args, req=['vif', 'mac']) - return d - - def vifctl_up(self, args): - """Entry point for 'vifctl up'. - """ - params = self.vifparams(args[1:]) - # Add the vif to its bridge. - Brctl.vif_bridge_add(params) - if params['ipaddr']: - # Add iptables rules for the ip addresses. - vif = params['vif'] - for ipaddr in params['ipaddr']: - Brctl.vif_restrict_addr(vif, ipaddr) - - def vifctl_down(self, args): - """Entry point for 'vifctl down'. - """ - params = self.vifparams(args[1:]) - # Remove the vif from its bridge. - Brctl.vif_bridge_rem(params) - if params['ip']: - # Remove iptables rules for the ip addresses. - vif = params['vif'] - for ip in params['ip']: - Brctl.vif_restrict_addr(vif, ip, delete=1) - - -if __name__ == "__main__": - VifControl().main(sys.argv) diff --git a/tools/xen/xend b/tools/xen/xend deleted file mode 100644 index 1e13e1450f..0000000000 --- a/tools/xen/xend +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/python -# -*- mode: python; -*- -# Copyright (C) 2004 Mike Wray - -"""Xen management daemon. Lives in /usr/sbin. - Provides console server and HTTP management api. - - Run: - - xend start - - The daemon is stopped with: - - xend stop - - The daemon should reconnect to device control interfaces - and recover its state when restarted. -""" -import os -import sys -from xen.xend.server import SrvDaemon - -def main(): - daemon = SrvDaemon.instance() - if not sys.argv[1:]: - print 'usage: %s {start|stop|restart}' % sys.argv[0] - elif os.fork(): - pid, status = os.wait() - return status >> 8 - elif sys.argv[1] == 'start': - return daemon.start() - elif sys.argv[1] == 'trace_start': - return daemon.start(trace=1) - elif sys.argv[1] == 'stop': - return daemon.stop() - elif sys.argv[1] == 'restart': - return daemon.stop() or daemon.start() - else: - print 'not an option:', sys.argv[1] - return 1 - -if __name__ == '__main__': - sys.exit(main()) diff --git a/tools/xen/xm b/tools/xen/xm deleted file mode 100755 index 09d8036f0f..0000000000 --- a/tools/xen/xm +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/python -# -*- mode: python; -*- -import sys -from xen.xm import main - -main.main(sys.argv) diff --git a/tools/xentrace/Makefile b/tools/xentrace/Makefile index f4319be6ed..fb90e2c125 100644 --- a/tools/xentrace/Makefile +++ b/tools/xentrace/Makefile @@ -1,10 +1,16 @@ +XEN_ROOT=../.. +include $(XEN_ROOT)/tools/Make.defs + CC = gcc CFLAGS = -Wall -O3 -Werror -CFLAGS += -I../../xen/include/hypervisor-ifs -CFLAGS += -I../../linux-xen-sparse/include -CFLAGS += -I../xu/lib -CFLAGS += -I../lib + +CFLAGS += -I $(XEN_HYPERVISOR_IFS) +CFLAGS += -I $(XEN_LINUX_INCLUDE) +CFLAGS += -I $(XEN_XC) +CFLAGS += -I $(XEN_XU) +CFLAGS += -I $(XEN_LIBXC) +CFLAGS += -I $(XEN_LIBXUTIL) HDRS = $(wildcard *.h) OBJS = $(patsubst %.c,%.o,$(wildcard *.c)) @@ -28,4 +34,4 @@ clean: $(RM) *.a *.so *.o *.rpm $(BIN) %: %.c $(HDRS) Makefile - $(CC) $(CFLAGS) -o $@ $< -L../xc/lib -lxc + $(CC) $(CFLAGS) -o $@ $< -L$(XEN_LIBXC) -lxc diff --git a/tools/xentrace/xentrace.c b/tools/xentrace/xentrace.c index 3560745a42..9972422878 100644 --- a/tools/xentrace/xentrace.c +++ b/tools/xentrace/xentrace.c @@ -21,7 +21,7 @@ #include #include -#include "../xc/lib/xc_private.h" +#include "xc_private.h" /* from xen/include/hypervisor-ifs */ #include diff --git a/tools/xu/Makefile b/tools/xu/Makefile deleted file mode 100644 index 6b31fd1f8b..0000000000 --- a/tools/xu/Makefile +++ /dev/null @@ -1,15 +0,0 @@ - -all: - python setup.py build - -install: all - if [ "$(prefix)" = "" ]; then \ - python setup.py install; \ - elif [ "$(dist)" = "yes" ]; then \ - python setup.py install --home="$(prefix)"; \ - else \ - python setup.py install --root="$(prefix)"; \ - fi - -clean: - rm -rf build *.pyc *.pyo *.a *.so *.o *~ *.rpm diff --git a/tools/xu/lib/__init__.py b/tools/xu/lib/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tools/xu/lib/domain_controller.h b/tools/xu/lib/domain_controller.h deleted file mode 100644 index 76dd164fcb..0000000000 --- a/tools/xu/lib/domain_controller.h +++ /dev/null @@ -1,532 +0,0 @@ -/****************************************************************************** - * domain_controller.h - * - * Interface to server controller (e.g., 'xend'). This header file defines the - * interface that is shared with guest OSes. - * - * Copyright (c) 2004, K A Fraser - */ - -#ifndef __DOMAIN_CONTROLLER_H__ -#define __DOMAIN_CONTROLLER_H__ - - -#ifndef BASIC_START_INFO -#error "Xen header file hypervisor-if.h must already be included here." -#endif - - -/* - * EXTENDED BOOTSTRAP STRUCTURE FOR NEW DOMAINS. - */ - -typedef struct { - BASIC_START_INFO; - u16 domain_controller_evtchn; /* 320 */ -} PACKED extended_start_info_t; /* 322 bytes */ -#define SIF_BLK_BE_DOMAIN (1<<4) /* Is this a block backend domain? */ -#define SIF_NET_BE_DOMAIN (1<<5) /* Is this a net backend domain? */ - - -/* - * Reason codes for SCHEDOP_shutdown. These are opaque to Xen but may be - * interpreted by control software to determine the appropriate action. These - * are only really advisories: the controller can actually do as it likes. - */ -#define SHUTDOWN_poweroff 0 /* Domain exited normally. Clean up and kill. */ -#define SHUTDOWN_reboot 1 /* Clean up, kill, and then restart. */ -#define SHUTDOWN_suspend 2 /* Clean up, save suspend info, kill. */ - - -/* - * CONTROLLER MESSAGING INTERFACE. - */ - -typedef struct { - u8 type; /* 0: echoed in response */ - u8 subtype; /* 1: echoed in response */ - u8 id; /* 2: echoed in response */ - u8 length; /* 3: number of bytes in 'msg' */ - u8 msg[60]; /* 4: type-specific message data */ -} PACKED control_msg_t; /* 64 bytes */ - -#define CONTROL_RING_SIZE 8 -typedef u32 CONTROL_RING_IDX; -#define MASK_CONTROL_IDX(_i) ((_i)&(CONTROL_RING_SIZE-1)) - -typedef struct { - control_msg_t tx_ring[CONTROL_RING_SIZE]; /* 0: guest -> controller */ - control_msg_t rx_ring[CONTROL_RING_SIZE]; /* 512: controller -> guest */ - CONTROL_RING_IDX tx_req_prod, tx_resp_prod; /* 1024, 1028 */ - CONTROL_RING_IDX rx_req_prod, rx_resp_prod; /* 1032, 1036 */ -} PACKED control_if_t; /* 1040 bytes */ - -/* - * Top-level command types. - */ -#define CMSG_CONSOLE 0 /* Console */ -#define CMSG_BLKIF_BE 1 /* Block-device backend */ -#define CMSG_BLKIF_FE 2 /* Block-device frontend */ -#define CMSG_NETIF_BE 3 /* Network-device backend */ -#define CMSG_NETIF_FE 4 /* Network-device frontend */ -#define CMSG_SHUTDOWN 6 /* Shutdown messages */ - - -/****************************************************************************** - * CONSOLE DEFINITIONS - */ - -/* - * Subtypes for console messages. - */ -#define CMSG_CONSOLE_DATA 0 - - -/****************************************************************************** - * BLOCK-INTERFACE FRONTEND DEFINITIONS - */ - -/* Messages from domain controller to guest. */ -#define CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED 0 - -/* Messages from guest to domain controller. */ -#define CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED 32 -#define CMSG_BLKIF_FE_INTERFACE_CONNECT 33 -#define CMSG_BLKIF_FE_INTERFACE_DISCONNECT 34 - -/* These are used by both front-end and back-end drivers. */ -#define blkif_vdev_t u16 -#define blkif_pdev_t u16 -#define blkif_sector_t u64 - -/* - * CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED: - * Notify a guest about a status change on one of its block interfaces. - * If the interface is DESTROYED or DOWN then the interface is disconnected: - * 1. The shared-memory frame is available for reuse. - * 2. Any unacknowledged messgaes pending on the interface were dropped. - */ -#define BLKIF_INTERFACE_STATUS_DESTROYED 0 /* Interface doesn't exist. */ -#define BLKIF_INTERFACE_STATUS_DISCONNECTED 1 /* Exists but is disconnected. */ -#define BLKIF_INTERFACE_STATUS_CONNECTED 2 /* Exists and is connected. */ -typedef struct { - u32 handle; /* 0 */ - u32 status; /* 4 */ - u16 evtchn; /* 8: (only if status == BLKIF_INTERFACE_STATUS_CONNECTED). */ -} PACKED blkif_fe_interface_status_changed_t; /* 10 bytes */ - -/* - * CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED: - * Notify the domain controller that the front-end driver is DOWN or UP. - * When the driver goes DOWN then the controller will send no more - * status-change notifications. When the driver comes UP then the controller - * will send a notification for each interface that currently exists. - * If the driver goes DOWN while interfaces are still UP, the domain - * will automatically take the interfaces DOWN. - */ -#define BLKIF_DRIVER_STATUS_DOWN 0 -#define BLKIF_DRIVER_STATUS_UP 1 -typedef struct { - /* IN */ - u32 status; /* 0: BLKIF_DRIVER_STATUS_??? */ - /* OUT */ - /* - * Tells driver how many interfaces it should expect to immediately - * receive notifications about. - */ - u32 nr_interfaces; /* 4 */ -} PACKED blkif_fe_driver_status_changed_t; /* 8 bytes */ - -/* - * CMSG_BLKIF_FE_INTERFACE_CONNECT: - * If successful, the domain controller will acknowledge with a - * STATUS_CONNECTED message. - */ -typedef struct { - u32 handle; /* 0 */ - u32 __pad; - memory_t shmem_frame; /* 8 */ - MEMORY_PADDING; -} PACKED blkif_fe_interface_connect_t; /* 16 bytes */ - -/* - * CMSG_BLKIF_FE_INTERFACE_DISCONNECT: - * If successful, the domain controller will acknowledge with a - * STATUS_DISCONNECTED message. - */ -typedef struct { - u32 handle; /* 0 */ -} PACKED blkif_fe_interface_disconnect_t; /* 4 bytes */ - - -/****************************************************************************** - * BLOCK-INTERFACE BACKEND DEFINITIONS - */ - -/* Messages from domain controller. */ -#define CMSG_BLKIF_BE_CREATE 0 /* Create a new block-device interface. */ -#define CMSG_BLKIF_BE_DESTROY 1 /* Destroy a block-device interface. */ -#define CMSG_BLKIF_BE_CONNECT 2 /* Connect i/f to remote driver. */ -#define CMSG_BLKIF_BE_DISCONNECT 3 /* Disconnect i/f from remote driver. */ -#define CMSG_BLKIF_BE_VBD_CREATE 4 /* Create a new VBD for an interface. */ -#define CMSG_BLKIF_BE_VBD_DESTROY 5 /* Delete a VBD from an interface. */ -#define CMSG_BLKIF_BE_VBD_GROW 6 /* Append an extent to a given VBD. */ -#define CMSG_BLKIF_BE_VBD_SHRINK 7 /* Remove last extent from a given VBD. */ - -/* Messages to domain controller. */ -#define CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED 32 - -/* - * Message request/response definitions for block-device messages. - */ - -typedef struct { - blkif_sector_t sector_start; /* 0 */ - blkif_sector_t sector_length; /* 8 */ - blkif_pdev_t device; /* 16 */ - u16 __pad; /* 18 */ -} PACKED blkif_extent_t; /* 20 bytes */ - -/* Non-specific 'okay' return. */ -#define BLKIF_BE_STATUS_OKAY 0 -/* Non-specific 'error' return. */ -#define BLKIF_BE_STATUS_ERROR 1 -/* The following are specific error returns. */ -#define BLKIF_BE_STATUS_INTERFACE_EXISTS 2 -#define BLKIF_BE_STATUS_INTERFACE_NOT_FOUND 3 -#define BLKIF_BE_STATUS_INTERFACE_CONNECTED 4 -#define BLKIF_BE_STATUS_VBD_EXISTS 5 -#define BLKIF_BE_STATUS_VBD_NOT_FOUND 6 -#define BLKIF_BE_STATUS_OUT_OF_MEMORY 7 -#define BLKIF_BE_STATUS_EXTENT_NOT_FOUND 8 -#define BLKIF_BE_STATUS_MAPPING_ERROR 9 - -/* This macro can be used to create an array of descriptive error strings. */ -#define BLKIF_BE_STATUS_ERRORS { \ - "Okay", \ - "Non-specific error", \ - "Interface already exists", \ - "Interface not found", \ - "Interface is still connected", \ - "VBD already exists", \ - "VBD not found", \ - "Out of memory", \ - "Extent not found for VBD", \ - "Could not map domain memory" } - -/* - * CMSG_BLKIF_BE_CREATE: - * When the driver sends a successful response then the interface is fully - * created. The controller will send a DOWN notification to the front-end - * driver. - */ -typedef struct { - /* IN */ - domid_t domid; /* 0: Domain attached to new interface. */ - u32 blkif_handle; /* 4: Domain-specific interface handle. */ - /* OUT */ - u32 status; /* 8 */ -} PACKED blkif_be_create_t; /* 12 bytes */ - -/* - * CMSG_BLKIF_BE_DESTROY: - * When the driver sends a successful response then the interface is fully - * torn down. The controller will send a DESTROYED notification to the - * front-end driver. - */ -typedef struct { - /* IN */ - domid_t domid; /* 0: Identify interface to be destroyed. */ - u32 blkif_handle; /* 4: ...ditto... */ - /* OUT */ - u32 status; /* 8 */ -} PACKED blkif_be_destroy_t; /* 12 bytes */ - -/* - * CMSG_BLKIF_BE_CONNECT: - * When the driver sends a successful response then the interface is fully - * connected. The controller will send a CONNECTED notification to the - * front-end driver. - */ -typedef struct { - /* IN */ - domid_t domid; /* 0: Domain attached to new interface. */ - u32 blkif_handle; /* 4: Domain-specific interface handle. */ - memory_t shmem_frame; /* 8: Page cont. shared comms window. */ - MEMORY_PADDING; - u32 evtchn; /* 16: Event channel for notifications. */ - /* OUT */ - u32 status; /* 20 */ -} PACKED blkif_be_connect_t; /* 24 bytes */ - -/* - * CMSG_BLKIF_BE_DISCONNECT: - * When the driver sends a successful response then the interface is fully - * disconnected. The controller will send a DOWN notification to the front-end - * driver. - */ -typedef struct { - /* IN */ - domid_t domid; /* 0: Domain attached to new interface. */ - u32 blkif_handle; /* 4: Domain-specific interface handle. */ - /* OUT */ - u32 status; /* 8 */ -} PACKED blkif_be_disconnect_t; /* 12 bytes */ - -/* CMSG_BLKIF_BE_VBD_CREATE */ -typedef struct { - /* IN */ - domid_t domid; /* 0: Identify blkdev interface. */ - u32 blkif_handle; /* 4: ...ditto... */ - blkif_vdev_t vdevice; /* 8: Interface-specific id for this VBD. */ - u16 readonly; /* 10: Non-zero -> VBD isn't writeable. */ - /* OUT */ - u32 status; /* 12 */ -} PACKED blkif_be_vbd_create_t; /* 16 bytes */ - -/* CMSG_BLKIF_BE_VBD_DESTROY */ -typedef struct { - /* IN */ - domid_t domid; /* 0: Identify blkdev interface. */ - u32 blkif_handle; /* 4: ...ditto... */ - blkif_vdev_t vdevice; /* 8: Interface-specific id of the VBD. */ - u16 __pad; /* 10 */ - /* OUT */ - u32 status; /* 12 */ -} PACKED blkif_be_vbd_destroy_t; /* 16 bytes */ - -/* CMSG_BLKIF_BE_VBD_GROW */ -typedef struct { - /* IN */ - domid_t domid; /* 0: Identify blkdev interface. */ - u32 blkif_handle; /* 4: ...ditto... */ - blkif_extent_t extent; /* 8: Physical extent to append to VBD. */ - blkif_vdev_t vdevice; /* 28: Interface-specific id of the VBD. */ - u16 __pad; /* 30 */ - /* OUT */ - u32 status; /* 32 */ -} PACKED blkif_be_vbd_grow_t; /* 36 bytes */ - -/* CMSG_BLKIF_BE_VBD_SHRINK */ -typedef struct { - /* IN */ - domid_t domid; /* 0: Identify blkdev interface. */ - u32 blkif_handle; /* 4: ...ditto... */ - blkif_vdev_t vdevice; /* 8: Interface-specific id of the VBD. */ - u16 __pad; /* 10 */ - /* OUT */ - u32 status; /* 12 */ -} PACKED blkif_be_vbd_shrink_t; /* 16 bytes */ - -/* - * CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED: - * Notify the domain controller that the back-end driver is DOWN or UP. - * If the driver goes DOWN while interfaces are still UP, the controller - * will automatically send DOWN notifications. - */ -typedef struct { - u32 status; /* 0: BLKIF_DRIVER_STATUS_??? */ -} PACKED blkif_be_driver_status_changed_t; /* 4 bytes */ - - -/****************************************************************************** - * NETWORK-INTERFACE FRONTEND DEFINITIONS - */ - -/* Messages from domain controller to guest. */ -#define CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED 0 - -/* Messages from guest to domain controller. */ -#define CMSG_NETIF_FE_DRIVER_STATUS_CHANGED 32 -#define CMSG_NETIF_FE_INTERFACE_CONNECT 33 -#define CMSG_NETIF_FE_INTERFACE_DISCONNECT 34 - -/* - * CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED: - * Notify a guest about a status change on one of its network interfaces. - * If the interface is DESTROYED or DOWN then the interface is disconnected: - * 1. The shared-memory frame is available for reuse. - * 2. Any unacknowledged messgaes pending on the interface were dropped. - */ -#define NETIF_INTERFACE_STATUS_DESTROYED 0 /* Interface doesn't exist. */ -#define NETIF_INTERFACE_STATUS_DISCONNECTED 1 /* Exists but is disconnected. */ -#define NETIF_INTERFACE_STATUS_CONNECTED 2 /* Exists and is connected. */ -typedef struct { - u32 handle; /* 0 */ - u32 status; /* 4 */ - u16 evtchn; /* 8: status == NETIF_INTERFACE_STATUS_CONNECTED */ - u8 mac[6]; /* 10: status == NETIF_INTERFACE_STATUS_CONNECTED */ -} PACKED netif_fe_interface_status_changed_t; /* 16 bytes */ - -/* - * CMSG_NETIF_FE_DRIVER_STATUS_CHANGED: - * Notify the domain controller that the front-end driver is DOWN or UP. - * When the driver goes DOWN then the controller will send no more - * status-change notifications. When the driver comes UP then the controller - * will send a notification for each interface that currently exists. - * If the driver goes DOWN while interfaces are still UP, the domain - * will automatically take the interfaces DOWN. - */ -#define NETIF_DRIVER_STATUS_DOWN 0 -#define NETIF_DRIVER_STATUS_UP 1 -typedef struct { - /* IN */ - u32 status; /* 0: NETIF_DRIVER_STATUS_??? */ - /* OUT */ - /* - * Tells driver how many interfaces it should expect to immediately - * receive notifications about. - */ - u32 nr_interfaces; /* 4 */ -} PACKED netif_fe_driver_status_changed_t; /* 8 bytes */ - -/* - * CMSG_NETIF_FE_INTERFACE_CONNECT: - * If successful, the domain controller will acknowledge with a - * STATUS_CONNECTED message. - */ -typedef struct { - u32 handle; /* 0 */ - u32 __pad; /* 4 */ - memory_t tx_shmem_frame; /* 8 */ - MEMORY_PADDING; - memory_t rx_shmem_frame; /* 16 */ - MEMORY_PADDING; -} PACKED netif_fe_interface_connect_t; /* 24 bytes */ - -/* - * CMSG_NETIF_FE_INTERFACE_DISCONNECT: - * If successful, the domain controller will acknowledge with a - * STATUS_DISCONNECTED message. - */ -typedef struct { - u32 handle; /* 0 */ -} PACKED netif_fe_interface_disconnect_t; /* 4 bytes */ - - -/****************************************************************************** - * NETWORK-INTERFACE BACKEND DEFINITIONS - */ - -/* Messages from domain controller. */ -#define CMSG_NETIF_BE_CREATE 0 /* Create a new net-device interface. */ -#define CMSG_NETIF_BE_DESTROY 1 /* Destroy a net-device interface. */ -#define CMSG_NETIF_BE_CONNECT 2 /* Connect i/f to remote driver. */ -#define CMSG_NETIF_BE_DISCONNECT 3 /* Disconnect i/f from remote driver. */ - -/* Messages to domain controller. */ -#define CMSG_NETIF_BE_DRIVER_STATUS_CHANGED 32 - -/* - * Message request/response definitions for net-device messages. - */ - -/* Non-specific 'okay' return. */ -#define NETIF_BE_STATUS_OKAY 0 -/* Non-specific 'error' return. */ -#define NETIF_BE_STATUS_ERROR 1 -/* The following are specific error returns. */ -#define NETIF_BE_STATUS_INTERFACE_EXISTS 2 -#define NETIF_BE_STATUS_INTERFACE_NOT_FOUND 3 -#define NETIF_BE_STATUS_INTERFACE_CONNECTED 4 -#define NETIF_BE_STATUS_OUT_OF_MEMORY 5 -#define NETIF_BE_STATUS_MAPPING_ERROR 6 - -/* This macro can be used to create an array of descriptive error strings. */ -#define NETIF_BE_STATUS_ERRORS { \ - "Okay", \ - "Non-specific error", \ - "Interface already exists", \ - "Interface not found", \ - "Interface is still connected", \ - "Out of memory", \ - "Could not map domain memory" } - -/* - * CMSG_NETIF_BE_CREATE: - * When the driver sends a successful response then the interface is fully - * created. The controller will send a DOWN notification to the front-end - * driver. - */ -typedef struct { - /* IN */ - domid_t domid; /* 0: Domain attached to new interface. */ - u32 netif_handle; /* 4: Domain-specific interface handle. */ - u8 mac[6]; /* 8 */ - u16 __pad; /* 14 */ - /* OUT */ - u32 status; /* 16 */ -} PACKED netif_be_create_t; /* 20 bytes */ - -/* - * CMSG_NETIF_BE_DESTROY: - * When the driver sends a successful response then the interface is fully - * torn down. The controller will send a DESTROYED notification to the - * front-end driver. - */ -typedef struct { - /* IN */ - domid_t domid; /* 0: Identify interface to be destroyed. */ - u32 netif_handle; /* 4: ...ditto... */ - /* OUT */ - u32 status; /* 8 */ -} PACKED netif_be_destroy_t; /* 12 bytes */ - -/* - * CMSG_NETIF_BE_CONNECT: - * When the driver sends a successful response then the interface is fully - * connected. The controller will send a CONNECTED notification to the - * front-end driver. - */ -typedef struct { - /* IN */ - domid_t domid; /* 0: Domain attached to new interface. */ - u32 netif_handle; /* 4: Domain-specific interface handle. */ - memory_t tx_shmem_frame; /* 8: Page cont. tx shared comms window. */ - MEMORY_PADDING; - memory_t rx_shmem_frame; /* 16: Page cont. rx shared comms window. */ - MEMORY_PADDING; - u16 evtchn; /* 24: Event channel for notifications. */ - u16 __pad; /* 26 */ - /* OUT */ - u32 status; /* 28 */ -} PACKED netif_be_connect_t; /* 32 bytes */ - -/* - * CMSG_NETIF_BE_DISCONNECT: - * When the driver sends a successful response then the interface is fully - * disconnected. The controller will send a DOWN notification to the front-end - * driver. - */ -typedef struct { - /* IN */ - domid_t domid; /* 0: Domain attached to new interface. */ - u32 netif_handle; /* 4: Domain-specific interface handle. */ - /* OUT */ - u32 status; /* 8 */ -} PACKED netif_be_disconnect_t; /* 12 bytes */ - -/* - * CMSG_NETIF_BE_DRIVER_STATUS_CHANGED: - * Notify the domain controller that the back-end driver is DOWN or UP. - * If the driver goes DOWN while interfaces are still UP, the domain - * will automatically send DOWN notifications. - */ -typedef struct { - u32 status; /* 0: NETIF_DRIVER_STATUS_??? */ -} PACKED netif_be_driver_status_changed_t; /* 4 bytes */ - - -/****************************************************************************** - * SHUTDOWN DEFINITIONS - */ - -/* - * Subtypes for shutdown messages. - */ -#define CMSG_SHUTDOWN_POWEROFF 0 /* Clean shutdown (SHUTDOWN_poweroff). */ -#define CMSG_SHUTDOWN_REBOOT 1 /* Clean shutdown (SHUTDOWN_reboot). */ -#define CMSG_SHUTDOWN_SUSPEND 2 /* Create suspend info, then */ - /* SHUTDOWN_suspend. */ - -#endif /* __DOMAIN_CONTROLLER_H__ */ diff --git a/tools/xu/lib/xu.c b/tools/xu/lib/xu.c deleted file mode 100644 index 48c975912d..0000000000 --- a/tools/xu/lib/xu.c +++ /dev/null @@ -1,1386 +0,0 @@ -/****************************************************************************** - * utils.c - * - * Copyright (c) 2004, K A Fraser - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "domain_controller.h" - -#include - -#define XENPKG "xen.ext.xu" - -/* Needed for Python versions earlier than 2.3. */ -#ifndef PyMODINIT_FUNC -#define PyMODINIT_FUNC DL_EXPORT(void) -#endif - -/* NB. The following should be kept in sync with the kernel's evtchn driver. */ -#define EVTCHN_DEV_NAME "/dev/xen/evtchn" -#define EVTCHN_DEV_MAJOR 10 -#define EVTCHN_DEV_MINOR 200 -#define PORT_NORMAL 0x0000 /* A standard event notification. */ -#define PORT_EXCEPTION 0x8000 /* An exceptional notification. */ -#define PORTIDX_MASK 0x7fff /* Strip subtype to obtain port index. */ -/* /dev/xen/evtchn ioctls: */ -/* EVTCHN_RESET: Clear and reinit the event buffer. Clear error condition. */ -#define EVTCHN_RESET _IO('E', 1) -/* EVTCHN_BIND: Bind to teh specified event-channel port. */ -#define EVTCHN_BIND _IO('E', 2) -/* EVTCHN_UNBIND: Unbind from the specified event-channel port. */ -#define EVTCHN_UNBIND _IO('E', 3) - -/* Size of a machine page frame. */ -#define PAGE_SIZE 4096 - - -/* - * *********************** NOTIFIER *********************** - */ - -typedef struct { - PyObject_HEAD; - int evtchn_fd; -} xu_notifier_object; - -static PyObject *xu_notifier_read(PyObject *self, PyObject *args) -{ - xu_notifier_object *xun = (xu_notifier_object *)self; - u16 v; - int bytes; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - while ( (bytes = read(xun->evtchn_fd, &v, sizeof(v))) == -1 ) - { - if ( errno == EINTR ) - continue; - if ( errno == EAGAIN ) - goto none; - return PyErr_SetFromErrno(PyExc_IOError); - } - - if ( bytes == sizeof(v) ) - return Py_BuildValue("(i,i)", v&PORTIDX_MASK, v&~PORTIDX_MASK); - - none: - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject *xu_notifier_unmask(PyObject *self, PyObject *args) -{ - xu_notifier_object *xun = (xu_notifier_object *)self; - u16 v; - int idx; - - if ( !PyArg_ParseTuple(args, "i", &idx) ) - return NULL; - - v = (u16)idx; - - (void)write(xun->evtchn_fd, &v, sizeof(v)); - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject *xu_notifier_bind(PyObject *self, PyObject *args) -{ - xu_notifier_object *xun = (xu_notifier_object *)self; - int idx; - - if ( !PyArg_ParseTuple(args, "i", &idx) ) - return NULL; - - if ( ioctl(xun->evtchn_fd, EVTCHN_BIND, idx) != 0 ) - return PyErr_SetFromErrno(PyExc_IOError); - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject *xu_notifier_unbind(PyObject *self, PyObject *args) -{ - xu_notifier_object *xun = (xu_notifier_object *)self; - int idx; - - if ( !PyArg_ParseTuple(args, "i", &idx) ) - return NULL; - - if ( ioctl(xun->evtchn_fd, EVTCHN_UNBIND, idx) != 0 ) - return PyErr_SetFromErrno(PyExc_IOError); - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject *xu_notifier_fileno(PyObject *self, PyObject *args) -{ - xu_notifier_object *xun = (xu_notifier_object *)self; - return PyInt_FromLong(xun->evtchn_fd); -} - -static PyMethodDef xu_notifier_methods[] = { - { "read", - (PyCFunction)xu_notifier_read, - METH_VARARGS, - "Read a (@port, @type) pair.\n" }, - - { "unmask", - (PyCFunction)xu_notifier_unmask, - METH_VARARGS, - "Unmask notifications for a @port.\n" }, - - { "bind", - (PyCFunction)xu_notifier_bind, - METH_VARARGS, - "Get notifications for a @port.\n" }, - - { "unbind", - (PyCFunction)xu_notifier_unbind, - METH_VARARGS, - "No longer get notifications for a @port.\n" }, - - { "fileno", - (PyCFunction)xu_notifier_fileno, - METH_VARARGS, - "Return the file descriptor for the notification channel.\n" }, - - { NULL, NULL, 0, NULL } -}; - -staticforward PyTypeObject xu_notifier_type; - -static PyObject *xu_notifier_new(PyObject *self, PyObject *args) -{ - xu_notifier_object *xun; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - xun = PyObject_New(xu_notifier_object, &xu_notifier_type); - - reopen: - xun->evtchn_fd = open(EVTCHN_DEV_NAME, O_NONBLOCK|O_RDWR); - if ( xun->evtchn_fd == -1 ) - { - if ( (errno == ENOENT) && - ((mkdir("/dev/xen", 0755) == 0) || (errno == EEXIST)) && - (mknod(EVTCHN_DEV_NAME, S_IFCHR|0600, - (EVTCHN_DEV_MAJOR << 8) | EVTCHN_DEV_MINOR) == 0) ) - goto reopen; - PyObject_Del((PyObject *)xun); - return PyErr_SetFromErrno(PyExc_IOError); - } - - return (PyObject *)xun; -} - -static PyObject *xu_notifier_getattr(PyObject *obj, char *name) -{ - if ( strcmp(name, "EXCEPTION") == 0 ) - return PyInt_FromLong(PORT_EXCEPTION); - if ( strcmp(name, "NORMAL") == 0 ) - return PyInt_FromLong(PORT_NORMAL); - return Py_FindMethod(xu_notifier_methods, obj, name); -} - -static void xu_notifier_dealloc(PyObject *self) -{ - xu_notifier_object *xun = (xu_notifier_object *)self; - (void)close(xun->evtchn_fd); - PyObject_Del(self); -} - -static PyTypeObject xu_notifier_type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "notifier", - sizeof(xu_notifier_object), - 0, - xu_notifier_dealloc, /* tp_dealloc */ - NULL, /* tp_print */ - xu_notifier_getattr, /* tp_getattr */ - NULL, /* tp_setattr */ - NULL, /* tp_compare */ - NULL, /* tp_repr */ - NULL, /* tp_as_number */ - NULL, /* tp_as_sequence */ - NULL, /* tp_as_mapping */ - NULL /* tp_hash */ -}; - - - -/* - * *********************** MESSAGE *********************** - */ - -#define TYPE(_x,_y) (((_x)<<8)|(_y)) -#define P2C(_struct, _field, _ctype) \ - do { \ - PyObject *obj; \ - if ( (obj = PyDict_GetItemString(payload, #_field)) != NULL ) \ - { \ - if ( PyInt_Check(obj) ) \ - { \ - ((_struct *)&xum->msg.msg[0])->_field = \ - (_ctype)PyInt_AsLong(obj); \ - dict_items_parsed++; \ - } \ - else if ( PyLong_Check(obj) ) \ - { \ - ((_struct *)&xum->msg.msg[0])->_field = \ - (_ctype)PyLong_AsUnsignedLongLong(obj); \ - dict_items_parsed++; \ - } \ - } \ - xum->msg.length = sizeof(_struct); \ - } while ( 0 ) -#define C2P(_struct, _field, _pytype, _ctype) \ - do { \ - PyObject *obj = Py ## _pytype ## _From ## _ctype \ - (((_struct *)&xum->msg.msg[0])->_field); \ - if ( dict == NULL ) dict = PyDict_New(); \ - PyDict_SetItemString(dict, #_field, obj); \ - } while ( 0 ) - -typedef struct { - PyObject_HEAD; - control_msg_t msg; -} xu_message_object; - -static PyObject *xu_message_append_payload(PyObject *self, PyObject *args) -{ - xu_message_object *xum = (xu_message_object *)self; - char *str; - int len; - - if ( !PyArg_ParseTuple(args, "s#", &str, &len) ) - return NULL; - - if ( (len + xum->msg.length) > sizeof(xum->msg.msg) ) - { - PyErr_SetString(PyExc_RuntimeError, "out of space in control message"); - return NULL; - } - - memcpy(&xum->msg.msg[xum->msg.length], str, len); - xum->msg.length += len; - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject *xu_message_set_response_fields(PyObject *self, PyObject *args) -{ - xu_message_object *xum = (xu_message_object *)self; - PyObject *payload; - int dict_items_parsed = 0; - - if ( !PyArg_ParseTuple(args, "O", &payload) ) - return NULL; - - if ( !PyDict_Check(payload) ) - { - PyErr_SetString(PyExc_TypeError, "payload is not a dictionary"); - return NULL; - } - - switch ( TYPE(xum->msg.type, xum->msg.subtype) ) - { - case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED): - P2C(blkif_fe_driver_status_changed_t, nr_interfaces, u32); - break; - case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED): - P2C(netif_fe_driver_status_changed_t, nr_interfaces, u32); - break; - } - - if ( dict_items_parsed != PyDict_Size(payload) ) - { - PyErr_SetString(PyExc_TypeError, "payload contains bad items"); - return NULL; - } - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject *xu_message_get_payload(PyObject *self, PyObject *args) -{ - xu_message_object *xum = (xu_message_object *)self; - PyObject *dict = NULL; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - switch ( TYPE(xum->msg.type, xum->msg.subtype) ) - { - case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED): - C2P(blkif_fe_interface_status_changed_t, handle, Int, Long); - C2P(blkif_fe_interface_status_changed_t, status, Int, Long); - C2P(blkif_fe_interface_status_changed_t, evtchn, Int, Long); - return dict; - case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED): - C2P(blkif_fe_driver_status_changed_t, status, Int, Long); - return dict; - case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_CONNECT): - C2P(blkif_fe_interface_connect_t, handle, Int, Long); - C2P(blkif_fe_interface_connect_t, shmem_frame, Int, Long); - return dict; - case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_DISCONNECT): - C2P(blkif_fe_interface_disconnect_t, handle, Int, Long); - return dict; - case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_CREATE): - C2P(blkif_be_create_t, domid, Int, Long); - C2P(blkif_be_create_t, blkif_handle, Int, Long); - C2P(blkif_be_create_t, status, Int, Long); - return dict; - case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DESTROY): - C2P(blkif_be_destroy_t, domid, Int, Long); - C2P(blkif_be_destroy_t, blkif_handle, Int, Long); - C2P(blkif_be_destroy_t, status, Int, Long); - return dict; - case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_CONNECT): - C2P(blkif_be_connect_t, domid, Int, Long); - C2P(blkif_be_connect_t, blkif_handle, Int, Long); - C2P(blkif_be_connect_t, shmem_frame, Int, Long); - C2P(blkif_be_connect_t, evtchn, Int, Long); - C2P(blkif_be_connect_t, status, Int, Long); - return dict; - case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DISCONNECT): - C2P(blkif_be_disconnect_t, domid, Int, Long); - C2P(blkif_be_disconnect_t, blkif_handle, Int, Long); - C2P(blkif_be_disconnect_t, status, Int, Long); - return dict; - case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_CREATE): - C2P(blkif_be_vbd_create_t, domid, Int, Long); - C2P(blkif_be_vbd_create_t, blkif_handle, Int, Long); - C2P(blkif_be_vbd_create_t, vdevice, Int, Long); - C2P(blkif_be_vbd_create_t, readonly, Int, Long); - C2P(blkif_be_vbd_create_t, status, Int, Long); - return dict; - case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_DESTROY): - C2P(blkif_be_vbd_destroy_t, domid, Int, Long); - C2P(blkif_be_vbd_destroy_t, blkif_handle, Int, Long); - C2P(blkif_be_vbd_destroy_t, vdevice, Int, Long); - C2P(blkif_be_vbd_destroy_t, status, Int, Long); - return dict; - case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_GROW): - C2P(blkif_be_vbd_grow_t, domid, Int, Long); - C2P(blkif_be_vbd_grow_t, blkif_handle, Int, Long); - C2P(blkif_be_vbd_grow_t, vdevice, Int, Long); - C2P(blkif_be_vbd_grow_t, extent.sector_start, - Long, UnsignedLongLong); - C2P(blkif_be_vbd_grow_t, extent.sector_length, - Long, UnsignedLongLong); - C2P(blkif_be_vbd_grow_t, extent.device, Int, Long); - C2P(blkif_be_vbd_grow_t, status, Int, Long); - return dict; - case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_SHRINK): - C2P(blkif_be_vbd_shrink_t, domid, Int, Long); - C2P(blkif_be_vbd_shrink_t, blkif_handle, Int, Long); - C2P(blkif_be_vbd_shrink_t, vdevice, Int, Long); - C2P(blkif_be_vbd_shrink_t, status, Int, Long); - return dict; - case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED): - C2P(blkif_be_driver_status_changed_t, status, Int, Long); - return dict; - case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED): - C2P(netif_fe_interface_status_changed_t, handle, Int, Long); - C2P(netif_fe_interface_status_changed_t, status, Int, Long); - C2P(netif_fe_interface_status_changed_t, evtchn, Int, Long); - return dict; - case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED): - C2P(netif_fe_driver_status_changed_t, status, Int, Long); - C2P(netif_fe_driver_status_changed_t, nr_interfaces, Int, Long); - return dict; - case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_CONNECT): - C2P(netif_fe_interface_connect_t, handle, Int, Long); - C2P(netif_fe_interface_connect_t, tx_shmem_frame, Int, Long); - C2P(netif_fe_interface_connect_t, rx_shmem_frame, Int, Long); - return dict; - case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_DISCONNECT): - C2P(netif_fe_interface_disconnect_t, handle, Int, Long); - return dict; - case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_CREATE): - C2P(netif_be_create_t, domid, Int, Long); - C2P(netif_be_create_t, netif_handle, Int, Long); - C2P(netif_be_create_t, status, Int, Long); - return dict; - case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DESTROY): - C2P(netif_be_destroy_t, domid, Int, Long); - C2P(netif_be_destroy_t, netif_handle, Int, Long); - C2P(netif_be_destroy_t, status, Int, Long); - return dict; - case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_CONNECT): - C2P(netif_be_connect_t, domid, Int, Long); - C2P(netif_be_connect_t, netif_handle, Int, Long); - C2P(netif_be_connect_t, tx_shmem_frame, Int, Long); - C2P(netif_be_connect_t, rx_shmem_frame, Int, Long); - C2P(netif_be_connect_t, evtchn, Int, Long); - C2P(netif_be_connect_t, status, Int, Long); - return dict; - case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DISCONNECT): - C2P(netif_be_disconnect_t, domid, Int, Long); - C2P(netif_be_disconnect_t, netif_handle, Int, Long); - C2P(netif_be_disconnect_t, status, Int, Long); - return dict; - case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DRIVER_STATUS_CHANGED): - C2P(netif_be_driver_status_changed_t, status, Int, Long); - return dict; - } - - return PyString_FromStringAndSize(xum->msg.msg, xum->msg.length); -} - -static PyObject *xu_message_get_header(PyObject *self, PyObject *args) -{ - xu_message_object *xum = (xu_message_object *)self; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - return Py_BuildValue("{s:i,s:i,s:i}", - "type", xum->msg.type, - "subtype", xum->msg.subtype, - "id", xum->msg.id); -} - -static PyMethodDef xu_message_methods[] = { - { "append_payload", - (PyCFunction)xu_message_append_payload, - METH_VARARGS, - "Append @str to the message payload.\n" }, - - { "set_response_fields", - (PyCFunction)xu_message_set_response_fields, - METH_VARARGS, - "Fill in the response fields in a message that was passed to us.\n" }, - - { "get_payload", - (PyCFunction)xu_message_get_payload, - METH_VARARGS, - "Return the message payload in string form.\n" }, - - { "get_header", - (PyCFunction)xu_message_get_header, - METH_VARARGS, - "Returns a dictionary of values for @type, @subtype, and @id.\n" }, - - { NULL, NULL, 0, NULL } -}; - -staticforward PyTypeObject xu_message_type; - -static PyObject *xu_message_new(PyObject *self, PyObject *args) -{ - xu_message_object *xum; - int type, subtype, id, dict_items_parsed = 0; - PyObject *payload = NULL; - - if ( !PyArg_ParseTuple(args, "iii|O", &type, &subtype, &id, &payload) ) - return NULL; - - xum = PyObject_New(xu_message_object, &xu_message_type); - - xum->msg.type = type; - xum->msg.subtype = subtype; - xum->msg.id = id; - xum->msg.length = 0; - - if ( payload == NULL ) - return (PyObject *)xum; - - if ( !PyDict_Check(payload) ) - { - PyErr_SetString(PyExc_TypeError, "payload is not a dictionary"); - PyObject_Del((PyObject *)xum); - return NULL; - } - - switch ( TYPE(type, subtype) ) - { - case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED): - P2C(blkif_fe_interface_status_changed_t, handle, u32); - P2C(blkif_fe_interface_status_changed_t, status, u32); - P2C(blkif_fe_interface_status_changed_t, evtchn, u16); - break; - case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_CREATE): - P2C(blkif_be_create_t, domid, u32); - P2C(blkif_be_create_t, blkif_handle, u32); - break; - case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DESTROY): - P2C(blkif_be_destroy_t, domid, u32); - P2C(blkif_be_destroy_t, blkif_handle, u32); - break; - case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_CONNECT): - P2C(blkif_be_connect_t, domid, u32); - P2C(blkif_be_connect_t, blkif_handle, u32); - P2C(blkif_be_connect_t, shmem_frame, memory_t); - P2C(blkif_be_connect_t, evtchn, u16); - break; - case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DISCONNECT): - P2C(blkif_be_disconnect_t, domid, u32); - P2C(blkif_be_disconnect_t, blkif_handle, u32); - break; - case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_CREATE): - P2C(blkif_be_vbd_create_t, domid, u32); - P2C(blkif_be_vbd_create_t, blkif_handle, u32); - P2C(blkif_be_vbd_create_t, vdevice, blkif_vdev_t); - P2C(blkif_be_vbd_create_t, readonly, u16); - break; - case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_DESTROY): - P2C(blkif_be_vbd_destroy_t, domid, u32); - P2C(blkif_be_vbd_destroy_t, blkif_handle, u32); - P2C(blkif_be_vbd_destroy_t, vdevice, blkif_vdev_t); - break; - case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_GROW): - P2C(blkif_be_vbd_grow_t, domid, u32); - P2C(blkif_be_vbd_grow_t, blkif_handle, u32); - P2C(blkif_be_vbd_grow_t, vdevice, blkif_vdev_t); - P2C(blkif_be_vbd_grow_t, extent.sector_start, blkif_sector_t); - P2C(blkif_be_vbd_grow_t, extent.sector_length, blkif_sector_t); - P2C(blkif_be_vbd_grow_t, extent.device, blkif_pdev_t); - break; - case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_SHRINK): - P2C(blkif_be_vbd_shrink_t, domid, u32); - P2C(blkif_be_vbd_shrink_t, blkif_handle, u32); - P2C(blkif_be_vbd_shrink_t, vdevice, blkif_vdev_t); - break; - case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED): - P2C(netif_fe_interface_status_changed_t, handle, u32); - P2C(netif_fe_interface_status_changed_t, status, u32); - P2C(netif_fe_interface_status_changed_t, evtchn, u16); - P2C(netif_fe_interface_status_changed_t, mac[0], u8); - P2C(netif_fe_interface_status_changed_t, mac[1], u8); - P2C(netif_fe_interface_status_changed_t, mac[2], u8); - P2C(netif_fe_interface_status_changed_t, mac[3], u8); - P2C(netif_fe_interface_status_changed_t, mac[4], u8); - P2C(netif_fe_interface_status_changed_t, mac[5], u8); - break; - case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_CREATE): - P2C(netif_be_create_t, domid, u32); - P2C(netif_be_create_t, netif_handle, u32); - P2C(netif_be_create_t, mac[0], u8); - P2C(netif_be_create_t, mac[1], u8); - P2C(netif_be_create_t, mac[2], u8); - P2C(netif_be_create_t, mac[3], u8); - P2C(netif_be_create_t, mac[4], u8); - P2C(netif_be_create_t, mac[5], u8); - break; - case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DESTROY): - P2C(netif_be_destroy_t, domid, u32); - P2C(netif_be_destroy_t, netif_handle, u32); - break; - case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_CONNECT): - P2C(netif_be_connect_t, domid, u32); - P2C(netif_be_connect_t, netif_handle, u32); - P2C(netif_be_connect_t, tx_shmem_frame, memory_t); - P2C(netif_be_connect_t, rx_shmem_frame, memory_t); - P2C(netif_be_connect_t, evtchn, u16); - break; - case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DISCONNECT): - P2C(netif_be_disconnect_t, domid, u32); - P2C(netif_be_disconnect_t, netif_handle, u32); - break; - case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED): - P2C(netif_fe_driver_status_changed_t, status, u32); - P2C(netif_fe_driver_status_changed_t, nr_interfaces, u32); - break; - } - - if ( dict_items_parsed != PyDict_Size(payload) ) - { - PyErr_SetString(PyExc_TypeError, "payload contains bad items"); - PyObject_Del((PyObject *)xum); - return NULL; - } - - return (PyObject *)xum; -} - -static PyObject *xu_message_getattr(PyObject *obj, char *name) -{ - xu_message_object *xum; - if ( strcmp(name, "MAX_PAYLOAD") == 0 ) - return PyInt_FromLong(sizeof(xum->msg.msg)); - return Py_FindMethod(xu_message_methods, obj, name); -} - -static void xu_message_dealloc(PyObject *self) -{ - PyObject_Del(self); -} - -static PyTypeObject xu_message_type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "message", - sizeof(xu_message_object), - 0, - xu_message_dealloc, /* tp_dealloc */ - NULL, /* tp_print */ - xu_message_getattr, /* tp_getattr */ - NULL, /* tp_setattr */ - NULL, /* tp_compare */ - NULL, /* tp_repr */ - NULL, /* tp_as_number */ - NULL, /* tp_as_sequence */ - NULL, /* tp_as_mapping */ - NULL /* tp_hash */ -}; - - - -/* - * *********************** PORT *********************** - */ - -static control_if_t *map_control_interface(int fd, unsigned long pfn) -{ - char *vaddr = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE, - MAP_SHARED, fd, pfn * PAGE_SIZE); - if ( vaddr == MAP_FAILED ) - return NULL; - return (control_if_t *)(vaddr + 2048); -} -static void unmap_control_interface(int fd, control_if_t *c) -{ - char *vaddr = (char *)c - 2048; - (void)munmap(vaddr, PAGE_SIZE); -} - -typedef struct xu_port_object { - PyObject_HEAD; - int mem_fd; - int xc_handle; - u32 remote_dom; - int local_port, remote_port; - control_if_t *interface; - CONTROL_RING_IDX tx_req_cons, tx_resp_prod; - CONTROL_RING_IDX rx_req_prod, rx_resp_cons; -} xu_port_object; - -static PyObject *port_error; - -static int xup_connect(xu_port_object *xup, domid_t dom, - int local_port, int remote_port){ - // From our prespective rx = producer, tx = consumer. - int err = 0; - printf("%s> dom=%u %d:%d\n", __FUNCTION__, (unsigned int)dom, - local_port, remote_port); - - // Consumer = tx. - //xup->interface->tx_resp_prod = 0; - //xup->interface->tx_req_prod = 0; - xup->tx_resp_prod = xup->interface->tx_resp_prod; - xup->tx_req_cons = xup->interface->tx_resp_prod; - printf("%s> tx: %u %u : %u %u\n", __FUNCTION__, - (unsigned int)xup->interface->tx_resp_prod, - (unsigned int)xup->tx_resp_prod, - (unsigned int)xup->tx_req_cons, - (unsigned int)xup->interface->tx_req_prod); - - // Producer = rx. - //xup->interface->rx_req_prod = 0; - //xup->interface->rx_resp_prod = 0; - xup->rx_req_prod = xup->interface->rx_req_prod; - xup->rx_resp_cons = xup->interface->rx_resp_prod; - printf("%s> rx: %u %u : %u %u\n", __FUNCTION__, - (unsigned int)xup->rx_resp_cons, - (unsigned int)xup->interface->rx_resp_prod, - (unsigned int)xup->interface->rx_req_prod, - (unsigned int)xup->rx_req_prod); - - xup->remote_dom = dom; - xup->local_port = local_port; - xup->remote_port = remote_port; - - printf("%s< err=%d\n", __FUNCTION__, err); - return err; -} - -static PyObject *xu_port_notify(PyObject *self, PyObject *args) -{ - xu_port_object *xup = (xu_port_object *)self; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - (void)xc_evtchn_send(xup->xc_handle, xup->local_port); - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject *xu_port_read_request(PyObject *self, PyObject *args) -{ - xu_port_object *xup = (xu_port_object *)self; - xu_message_object *xum; - CONTROL_RING_IDX c = xup->tx_req_cons; - control_if_t *cif = xup->interface; - control_msg_t *cmsg; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - if ( (c == cif->tx_req_prod) || - ((c - xup->tx_resp_prod) == CONTROL_RING_SIZE) ) - { - PyErr_SetString(port_error, "no request to read"); - return NULL; - } - - cmsg = &cif->tx_ring[MASK_CONTROL_IDX(c)]; - xum = PyObject_New(xu_message_object, &xu_message_type); - memcpy(&xum->msg, cmsg, sizeof(*cmsg)); - if ( xum->msg.length > sizeof(xum->msg.msg) ) - xum->msg.length = sizeof(xum->msg.msg); - xup->tx_req_cons++; - return (PyObject *)xum; -} - -static PyObject *xu_port_write_request(PyObject *self, PyObject *args) -{ - xu_port_object *xup = (xu_port_object *)self; - xu_message_object *xum; - CONTROL_RING_IDX p = xup->rx_req_prod; - control_if_t *cif = xup->interface; - control_msg_t *cmsg; - - if ( !PyArg_ParseTuple(args, "O", (PyObject **)&xum) ) - return NULL; - - if ( !PyObject_TypeCheck((PyObject *)xum, &xu_message_type) ) - { - PyErr_SetString(PyExc_TypeError, "expected a " XENPKG ".message"); - return NULL; - } - - if ( ((p - xup->rx_resp_cons) == CONTROL_RING_SIZE) ) - { - PyErr_SetString(port_error, "no space to write request"); - return NULL; - } - - cmsg = &cif->rx_ring[MASK_CONTROL_IDX(p)]; - memcpy(cmsg, &xum->msg, sizeof(*cmsg)); - - xup->rx_req_prod = cif->rx_req_prod = p + 1; - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject *xu_port_read_response(PyObject *self, PyObject *args) -{ - xu_port_object *xup = (xu_port_object *)self; - xu_message_object *xum; - CONTROL_RING_IDX c = xup->rx_resp_cons; - control_if_t *cif = xup->interface; - control_msg_t *cmsg; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - if ( (c == cif->rx_resp_prod) || (c == xup->rx_req_prod) ) - { - PyErr_SetString(port_error, "no response to read"); - return NULL; - } - - cmsg = &cif->rx_ring[MASK_CONTROL_IDX(c)]; - xum = PyObject_New(xu_message_object, &xu_message_type); - memcpy(&xum->msg, cmsg, sizeof(*cmsg)); - if ( xum->msg.length > sizeof(xum->msg.msg) ) - xum->msg.length = sizeof(xum->msg.msg); - xup->rx_resp_cons++; - return (PyObject *)xum; -} - -static PyObject *xu_port_write_response(PyObject *self, PyObject *args) -{ - xu_port_object *xup = (xu_port_object *)self; - xu_message_object *xum; - CONTROL_RING_IDX p = xup->tx_resp_prod; - control_if_t *cif = xup->interface; - control_msg_t *cmsg; - - if ( !PyArg_ParseTuple(args, "O", (PyObject **)&xum) ) - return NULL; - - if ( !PyObject_TypeCheck((PyObject *)xum, &xu_message_type) ) - { - PyErr_SetString(PyExc_TypeError, "expected a " XENPKG ".message"); - return NULL; - } - - if ( p == xup->tx_req_cons ) - { - PyErr_SetString(port_error, "no space to write response"); - return NULL; - } - - cmsg = &cif->tx_ring[MASK_CONTROL_IDX(p)]; - memcpy(cmsg, &xum->msg, sizeof(*cmsg)); - - xup->tx_resp_prod = cif->tx_resp_prod = p + 1; - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject *xu_port_request_to_read(PyObject *self, PyObject *args) -{ - xu_port_object *xup = (xu_port_object *)self; - CONTROL_RING_IDX c = xup->tx_req_cons; - control_if_t *cif = xup->interface; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - if ( (c == cif->tx_req_prod) || - ((c - xup->tx_resp_prod) == CONTROL_RING_SIZE) ) - return PyInt_FromLong(0); - - return PyInt_FromLong(1); -} - -static PyObject *xu_port_space_to_write_request(PyObject *self, PyObject *args) -{ - xu_port_object *xup = (xu_port_object *)self; - CONTROL_RING_IDX p = xup->rx_req_prod; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - if ( ((p - xup->rx_resp_cons) == CONTROL_RING_SIZE) ) - return PyInt_FromLong(0); - - return PyInt_FromLong(1); -} - -static PyObject *xu_port_response_to_read(PyObject *self, PyObject *args) -{ - xu_port_object *xup = (xu_port_object *)self; - CONTROL_RING_IDX c = xup->rx_resp_cons; - control_if_t *cif = xup->interface; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - if ( (c == cif->rx_resp_prod) || (c == xup->rx_req_prod) ) - return PyInt_FromLong(0); - - return PyInt_FromLong(1); -} - -static PyObject *xu_port_space_to_write_response( - PyObject *self, PyObject *args) -{ - xu_port_object *xup = (xu_port_object *)self; - CONTROL_RING_IDX p = xup->tx_resp_prod; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - if ( p == xup->tx_req_cons ) - return PyInt_FromLong(0); - - return PyInt_FromLong(1); -} - -static PyMethodDef xu_port_methods[] = { - { "notify", - (PyCFunction)xu_port_notify, - METH_VARARGS, - "Send a notification to the remote end.\n" }, - - { "read_request", - (PyCFunction)xu_port_read_request, - METH_VARARGS, - "Read a request message from the control interface.\n" }, - - { "write_request", - (PyCFunction)xu_port_write_request, - METH_VARARGS, - "Write a request message to the control interface.\n" }, - - { "read_response", - (PyCFunction)xu_port_read_response, - METH_VARARGS, - "Read a response message from the control interface.\n" }, - - { "write_response", - (PyCFunction)xu_port_write_response, - METH_VARARGS, - "Write a response message to the control interface.\n" }, - - { "request_to_read", - (PyCFunction)xu_port_request_to_read, - METH_VARARGS, - "Returns TRUE if there is a request message to read.\n" }, - - { "space_to_write_request", - (PyCFunction)xu_port_space_to_write_request, - METH_VARARGS, - "Returns TRUE if there is space to write a request message.\n" }, - - { "response_to_read", - (PyCFunction)xu_port_response_to_read, - METH_VARARGS, - "Returns TRUE if there is a response message to read.\n" }, - - { "space_to_write_response", - (PyCFunction)xu_port_space_to_write_response, - METH_VARARGS, - "Returns TRUE if there is space to write a response message.\n" }, - - { NULL, NULL, 0, NULL } -}; - -staticforward PyTypeObject xu_port_type; - -static PyObject *xu_port_new(PyObject *self, PyObject *args) -{ - xu_port_object *xup; - u32 dom; - int port1, port2; - xc_dominfo_t info; - - if ( !PyArg_ParseTuple(args, "i", &dom) ) - return NULL; - - xup = PyObject_New(xu_port_object, &xu_port_type); - - if ( (xup->mem_fd = open("/dev/mem", O_RDWR)) == -1 ) - { - PyErr_SetString(port_error, "Could not open '/dev/mem'"); - goto fail1; - } - - /* Set the General-Purpose Subject whose page frame will be mapped. */ - (void)ioctl(xup->mem_fd, _IO('M', 1), (unsigned long)dom); - - if ( (xup->xc_handle = xc_interface_open()) == -1 ) - { - PyErr_SetString(port_error, "Could not open Xen control interface"); - goto fail2; - } - - if ( dom == 0 ) - { - /* - * The control-interface event channel for DOM0 is already set up. - * We use an ioctl to discover the port at our end of the channel. - */ - port1 = ioctl(xup->xc_handle, IOCTL_PRIVCMD_INITDOMAIN_EVTCHN, NULL); - port2 = -1; /* We don't need the remote end of the DOM0 link. */ - if ( port1 < 0 ) - { - PyErr_SetString(port_error, "Could not open channel to DOM0"); - goto fail3; - } - } - else if ( xc_evtchn_bind_interdomain(xup->xc_handle, - DOMID_SELF, dom, - &port1, &port2) != 0 ) - { - PyErr_SetString(port_error, "Could not open channel to domain"); - goto fail3; - } - - if ( (xc_domain_getinfo(xup->xc_handle, dom, 1, &info) != 1) || - (info.domid != dom) ) - { - PyErr_SetString(port_error, "Failed to obtain domain status"); - goto fail4; - } - - xup->interface = - map_control_interface(xup->mem_fd, info.shared_info_frame); - if ( xup->interface == NULL ) - { - PyErr_SetString(port_error, "Failed to map domain control interface"); - goto fail4; - } - - xup_connect(xup, dom, port1, port2); - return (PyObject *)xup; - - - fail4: - (void)xc_evtchn_close(xup->xc_handle, DOMID_SELF, port1); - fail3: - (void)xc_interface_close(xup->xc_handle); - fail2: - (void)close(xup->mem_fd); - fail1: - PyObject_Del((PyObject *)xup); - return NULL; -} - -static PyObject *xu_port_getattr(PyObject *obj, char *name) -{ - xu_port_object *xup = (xu_port_object *)obj; - if ( strcmp(name, "local_port") == 0 ) - return PyInt_FromLong(xup->local_port); - if ( strcmp(name, "remote_port") == 0 ) - return PyInt_FromLong(xup->remote_port); - if ( strcmp(name, "remote_dom") == 0 ) - return PyInt_FromLong(xup->remote_dom); - return Py_FindMethod(xu_port_methods, obj, name); -} - -static void xu_port_dealloc(PyObject *self) -{ - xu_port_object *xup = (xu_port_object *)self; - unmap_control_interface(xup->mem_fd, xup->interface); - if ( xup->remote_dom != 0 ) - (void)xc_evtchn_close(xup->xc_handle, DOMID_SELF, xup->local_port); - (void)xc_interface_close(xup->xc_handle); - (void)close(xup->mem_fd); - PyObject_Del(self); -} - -static PyTypeObject xu_port_type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "port", - sizeof(xu_port_object), - 0, - xu_port_dealloc, /* tp_dealloc */ - NULL, /* tp_print */ - xu_port_getattr, /* tp_getattr */ - NULL, /* tp_setattr */ - NULL, /* tp_compare */ - NULL, /* tp_repr */ - NULL, /* tp_as_number */ - NULL, /* tp_as_sequence */ - NULL, /* tp_as_mapping */ - NULL /* tp_hash */ -}; - - - -/* - * *********************** BUFFER *********************** - */ - -#define BUFSZ 65536 -#define MASK_BUF_IDX(_i) ((_i)&(BUFSZ-1)) -typedef unsigned int BUF_IDX; - -typedef struct { - PyObject_HEAD; - char *buf; - unsigned int prod, cons; -} xu_buffer_object; - -static PyObject *__xu_buffer_peek(xu_buffer_object *xub, int max) -{ - PyObject *str1, *str2; - int len1, len2, c = MASK_BUF_IDX(xub->cons); - - len1 = xub->prod - xub->cons; - if ( len1 > (BUFSZ - c) ) /* clip to ring wrap */ - len1 = BUFSZ - c; - if ( len1 > max ) /* clip to specified maximum */ - len1 = max; - if ( len1 < 0 ) /* sanity */ - len1 = 0; - - if ( (str1 = PyString_FromStringAndSize(&xub->buf[c], len1)) == NULL ) - return NULL; - - if ( (len1 < (xub->prod - xub->cons)) && (len1 < max) ) - { - len2 = max - len1; - if ( len2 > MASK_BUF_IDX(xub->prod) ) - len2 = MASK_BUF_IDX(xub->prod); - if ( len2 > 0 ) - { - str2 = PyString_FromStringAndSize(&xub->buf[0], len2); - if ( str2 == NULL ) - return NULL; - PyString_ConcatAndDel(&str1, str2); - if ( str1 == NULL ) - return NULL; - } - } - - return str1; -} - -static PyObject *xu_buffer_peek(PyObject *self, PyObject *args) -{ - xu_buffer_object *xub = (xu_buffer_object *)self; - int max = 1024; - - if ( !PyArg_ParseTuple(args, "|i", &max) ) - return NULL; - - return __xu_buffer_peek(xub, max); -} - -static PyObject *xu_buffer_read(PyObject *self, PyObject *args) -{ - xu_buffer_object *xub = (xu_buffer_object *)self; - PyObject *str; - int max = 1024; - - if ( !PyArg_ParseTuple(args, "|i", &max) ) - return NULL; - - if ( (str = __xu_buffer_peek(xub, max)) != NULL ) - xub->cons += PyString_Size(str); - - return str; -} - -static PyObject *xu_buffer_discard(PyObject *self, PyObject *args) -{ - xu_buffer_object *xub = (xu_buffer_object *)self; - int max, len; - - if ( !PyArg_ParseTuple(args, "i", &max) ) - return NULL; - - len = xub->prod - xub->cons; - if ( len > max ) - len = max; - if ( len < 0 ) - len = 0; - - xub->cons += len; - - return PyInt_FromLong(len); -} - -static PyObject *xu_buffer_write(PyObject *self, PyObject *args) -{ - xu_buffer_object *xub = (xu_buffer_object *)self; - char *str; - int len, len1, len2; - - if ( !PyArg_ParseTuple(args, "s#", &str, &len) ) - return NULL; - - len1 = len; - if ( len1 > (BUFSZ - MASK_BUF_IDX(xub->prod)) ) - len1 = BUFSZ - MASK_BUF_IDX(xub->prod); - if ( len1 > (BUFSZ - (xub->prod - xub->cons)) ) - len1 = BUFSZ - (xub->prod - xub->cons); - - if ( len1 == 0 ) - return PyInt_FromLong(0); - - memcpy(&xub->buf[MASK_BUF_IDX(xub->prod)], &str[0], len1); - xub->prod += len1; - - if ( len1 < len ) - { - len2 = len - len1; - if ( len2 > (BUFSZ - MASK_BUF_IDX(xub->prod)) ) - len2 = BUFSZ - MASK_BUF_IDX(xub->prod); - if ( len2 > (BUFSZ - (xub->prod - xub->cons)) ) - len2 = BUFSZ - (xub->prod - xub->cons); - if ( len2 != 0 ) - { - memcpy(&xub->buf[MASK_BUF_IDX(xub->prod)], &str[len1], len2); - xub->prod += len2; - return PyInt_FromLong(len1 + len2); - } - } - - return PyInt_FromLong(len1); -} - -static PyObject *xu_buffer_empty(PyObject *self, PyObject *args) -{ - xu_buffer_object *xub = (xu_buffer_object *)self; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - if ( xub->cons == xub->prod ) - return PyInt_FromLong(1); - - return PyInt_FromLong(0); -} - -static PyObject *xu_buffer_full(PyObject *self, PyObject *args) -{ - xu_buffer_object *xub = (xu_buffer_object *)self; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - if ( (xub->prod - xub->cons) == BUFSZ ) - return PyInt_FromLong(1); - - return PyInt_FromLong(0); -} - -static PyMethodDef xu_buffer_methods[] = { - { "peek", - (PyCFunction)xu_buffer_peek, - METH_VARARGS, - "Peek up to @max bytes from the buffer. Returns a string.\n" }, - - { "read", - (PyCFunction)xu_buffer_read, - METH_VARARGS, - "Read up to @max bytes from the buffer. Returns a string.\n" }, - - { "discard", - (PyCFunction)xu_buffer_discard, - METH_VARARGS, - "Discard up to @max bytes from the buffer. Returns number of bytes.\n" }, - - { "write", - (PyCFunction)xu_buffer_write, - METH_VARARGS, - "Write @string into buffer. Return number of bytes written.\n" }, - - { "empty", - (PyCFunction)xu_buffer_empty, - METH_VARARGS, - "Return TRUE if the buffer is empty.\n" }, - - { "full", - (PyCFunction)xu_buffer_full, - METH_VARARGS, - "Return TRUE if the buffer is full.\n" }, - - { NULL, NULL, 0, NULL } -}; - -staticforward PyTypeObject xu_buffer_type; - -static PyObject *xu_buffer_new(PyObject *self, PyObject *args) -{ - xu_buffer_object *xub; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - xub = PyObject_New(xu_buffer_object, &xu_buffer_type); - - if ( (xub->buf = malloc(BUFSZ)) == NULL ) - { - PyObject_Del((PyObject *)xub); - return NULL; - } - - xub->prod = xub->cons = 0; - - return (PyObject *)xub; -} - -static PyObject *xu_buffer_getattr(PyObject *obj, char *name) -{ - return Py_FindMethod(xu_buffer_methods, obj, name); -} - -static void xu_buffer_dealloc(PyObject *self) -{ - xu_buffer_object *xub = (xu_buffer_object *)self; - free(xub->buf); - PyObject_Del(self); -} - -static PyTypeObject xu_buffer_type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "buffer", - sizeof(xu_buffer_object), - 0, - xu_buffer_dealloc, /* tp_dealloc */ - NULL, /* tp_print */ - xu_buffer_getattr, /* tp_getattr */ - NULL, /* tp_setattr */ - NULL, /* tp_compare */ - NULL, /* tp_repr */ - NULL, /* tp_as_number */ - NULL, /* tp_as_sequence */ - NULL, /* tp_as_mapping */ - NULL /* tp_hash */ -}; - - - -/* - * *********************** MODULE WRAPPER *********************** - */ - -static void handle_child_death(int dummy) -{ - while ( waitpid(-1, NULL, WNOHANG) > 0 ) - continue; -} - -static PyObject *xu_autoreap(PyObject *self, PyObject *args) -{ - struct sigaction sa; - - if ( !PyArg_ParseTuple(args, "") ) - return NULL; - - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = handle_child_death; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_NOCLDSTOP | SA_RESTART; - (void)sigaction(SIGCHLD, &sa, NULL); - - Py_INCREF(Py_None); - return Py_None; -} - -static PyMethodDef xu_methods[] = { - { "notifier", xu_notifier_new, METH_VARARGS, - "Create a new notifier." }, - { "message", xu_message_new, METH_VARARGS, - "Create a new communications message." }, - { "port", xu_port_new, METH_VARARGS, - "Create a new communications port." }, - { "buffer", xu_buffer_new, METH_VARARGS, - "Create a new ring buffer." }, - { "autoreap", xu_autoreap, METH_VARARGS, - "Ensure that zombie children are automatically reaped by the OS." }, - { NULL, NULL, 0, NULL } -}; - -PyMODINIT_FUNC initxu(void) -{ - PyObject *m, *d; - - m = Py_InitModule(XENPKG, xu_methods); - - d = PyModule_GetDict(m); - port_error = PyErr_NewException(XENPKG ".PortError", NULL, NULL); - PyDict_SetItemString(d, "PortError", port_error); -} diff --git a/tools/xu/setup.py b/tools/xu/setup.py deleted file mode 100644 index e342c78a14..0000000000 --- a/tools/xu/setup.py +++ /dev/null @@ -1,19 +0,0 @@ - -from distutils.core import setup, Extension - -xu = Extension("xu", - extra_compile_args = ["-fno-strict-aliasing"], - include_dirs = ["../xc/lib", - "../../xen/include/hypervisor-ifs", - "../../linux-xen-sparse/include"], - library_dirs = ["../xc/lib"], - libraries = ["xc"], - sources = ["lib/xu.c"]) - -setup(name = "xu", - version = "1.0", - #packages = ["xend"], - #package_dir = { "xend" : "lib" }, - ext_package = "xen.ext", - ext_modules = [ xu ] - )